// Generated by nautilus-codegen. Do not edit manually.
import { NautilusClient } from '../_internal/_client';
import { NotFoundError } from '../_internal/_errors';
{%- if has_enums %}
import { {% for e in enum_imports %}{{ e }}{% if not loop.last %}, {% endif %}{% endfor %} } from '../enums';
{%- endif %}
{%- if has_composite_types %}
import { {% for t in composite_type_imports %}{{ t }}{% if not loop.last %}, {% endif %}{% endfor %} } from '../types';
{%- endif %}
/** Maps `table__dbColumn` keys returned by the engine to JS field names. */
const _{{ table_name }}RowMap: Record<string, string> = {
{%- for f in scalar_fields %}
'{{ table_name }}__{{ f.db_name }}': '{{ f.name }}',
{%- endfor %}
};
const _{{ table_name }}Fields = new Set<string>([
{%- for f in scalar_fields %}
'{{ f.name }}',
{%- endfor %}
]);
const _{{ table_name }}ArrayFields = new Set<string>([
{%- for f in scalar_fields %}
{%- if f.is_array %}
'{{ f.name }}',
{%- endif %}
{%- endfor %}
]);
const _{{ table_name }}BooleanFields = new Set<string>([
{%- for f in scalar_fields %}
{%- if f.base_type == "boolean" %}
'{{ f.name }}',
{%- endif %}
{%- endfor %}
]);
/** Maps JS / logical field names to DB column names (handles @map renames). */
const _{{ table_name }}FieldToDb: Record<string, string> = {
{%- for f in scalar_fields %}
'{{ f.logical_name }}': '{{ f.db_name }}',
{%- if f.name != f.logical_name %}
'{{ f.name }}': '{{ f.db_name }}',
{%- endif %}
{%- endfor %}
};
function _coerceBooleanValue(value: unknown): unknown {
if (typeof value === 'boolean') return value;
if (typeof value === 'number' && (value === 0 || value === 1)) return value === 1;
if (typeof value === 'string') {
const normalized = value.toLowerCase();
if (normalized === 'true' || normalized === '1') return true;
if (normalized === 'false' || normalized === '0') return false;
}
return value;
}
function _coerce{{ model_name }}(row: Record<string, unknown>): {{ model_name }}Model {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(row)) {
const field = _{{ table_name }}RowMap[k] ?? k;
if (!_{{ table_name }}Fields.has(field)) continue;
if (v == null) {
out[field] = _{{ table_name }}ArrayFields.has(field) ? [] : null;
continue;
}
let coerced: unknown = _{{ table_name }}BooleanFields.has(field)
? _coerceBooleanValue(v)
: v;
{%- for f in scalar_fields %}
{%- if f.base_type == "Date" %}
if (field === '{{ f.name }}' && typeof v === 'string') coerced = new Date(v);
{%- elif f.base_type == "Buffer" %}
if (field === '{{ f.name }}' && typeof v === 'string') coerced = Buffer.from(v, 'base64');
{%- endif %}
{%- endfor %}
out[field] = coerced;
}
return out as {{ model_name }}Model;
}
export interface StringFilter {
contains?: string;
startsWith?: string;
endsWith?: string;
in?: string[];
notIn?: string[];
not?: string;
isNull?: boolean;
}
export interface NumberFilter {
lt?: number;
lte?: number;
gt?: number;
gte?: number;
in?: number[];
notIn?: number[];
not?: number;
isNull?: boolean;
}
export interface DateFilter {
lt?: Date;
lte?: Date;
gt?: Date;
gte?: Date;
in?: Date[];
notIn?: Date[];
not?: Date;
isNull?: boolean;
}
export type SortOrder = 'asc' | 'desc';
export interface {{ model_name }}Model {
{%- for f in scalar_fields %}
{{ f.name }}{% if not f.is_pk %}?{% endif %}: {{ f.ts_type }};
{%- endfor %}
{%- for f in relation_fields %}
{{ f.name }}?: {{ f.ts_type }};
{%- endfor %}
}
export interface {{ model_name }}WhereInput {
{%- for field in where_input_fields %}
{%- if field.base_type == "string" %}
{{ field.name }}?: string | StringFilter;
{%- elif field.base_type == "number" %}
{{ field.name }}?: number | NumberFilter;
{%- elif field.base_type == "Date" %}
{{ field.name }}?: Date | DateFilter;
{%- elif field.base_type == "boolean" %}
{{ field.name }}?: boolean;
{%- else %}
{{ field.name }}?: {{ field.ts_type }};
{%- endif %}
{%- endfor %}
AND?: {{ model_name }}WhereInput | {{ model_name }}WhereInput[];
OR?: {{ model_name }}WhereInput[];
NOT?: {{ model_name }}WhereInput | {{ model_name }}WhereInput[];
}
export interface {{ model_name }}CreateInput {
{%- for field in create_input_fields %}
{%- if field.is_required %}
{{ field.name }}: {{ field.ts_type }};
{%- else %}
{{ field.name }}?: {{ field.ts_type }};
{%- endif %}
{%- endfor %}
}
export interface {{ model_name }}UpdateInput {
{%- for field in update_input_fields %}
{{ field.name }}?: {{ field.ts_type }};
{%- endfor %}
}
export interface {{ model_name }}OrderByInput {
{%- for field in order_by_fields %}
{{ field.name }}?: SortOrder;
{%- endfor %}
}
export interface {{ model_name }}SelectInput {
{%- for field in scalar_fields %}
{{ field.name }}?: boolean;
{%- endfor %}
}
{%- if has_includes %}
export interface {{ model_name }}IncludeInput {
{%- for field in include_fields %}
{{ field.name }}?: boolean | FindMany{{ field.target_model }}ArgsFrom{{ model_name }};
{%- endfor %}
}
{%- for field in include_fields %}
export interface FindMany{{ field.target_model }}ArgsFrom{{ model_name }} {
where?: {{ field.target_model }}WhereInput;
orderBy?: {{ field.target_model }}OrderByInput;
{%- if field.is_array %}
take?: number;
skip?: number;
cursor?: Record<string, unknown>;
distinct?: string[];
{%- endif %}
include?: {{ field.target_model }}IncludeInput;
}
{%- endfor %}
{%- endif %}
export interface {{ model_name }}UpsertInput {
create: {{ model_name }}CreateInput;
update: {{ model_name }}UpdateInput;
}
export type {{ model_name }}ScalarFieldKeys = {% for f in scalar_fields %}'{{ f.name }}'{% if not loop.last %} | {% endif %}{% endfor %};
export interface {{ model_name }}CountAggregateInput {
_all?: boolean;
{%- for f in scalar_fields %}
{{ f.name }}?: boolean;
{%- endfor %}
}
{%- if has_numeric_fields %}
export interface {{ model_name }}AvgAggregateInput {
{%- for f in numeric_fields %}
{{ f.name }}?: boolean;
{%- endfor %}
}
export interface {{ model_name }}SumAggregateInput {
{%- for f in numeric_fields %}
{{ f.name }}?: boolean;
{%- endfor %}
}
{%- endif %}
export interface {{ model_name }}MinAggregateInput {
{%- for f in orderable_fields %}
{{ f.name }}?: boolean;
{%- endfor %}
}
export interface {{ model_name }}MaxAggregateInput {
{%- for f in orderable_fields %}
{{ f.name }}?: boolean;
{%- endfor %}
}
export interface {{ model_name }}GroupByOutput {
{%- for f in scalar_fields %}
{{ f.name }}?: {{ f.ts_type }};
{%- endfor %}
_count?: Record<string, number>;
_avg?: Record<string, number>;
_sum?: Record<string, unknown>;
_min?: Record<string, unknown>;
_max?: Record<string, unknown>;
}
function _processWhereFilters(
where: Record<string, unknown>,
fieldToDb: Record<string, string>,
): Record<string, unknown> {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(where)) {
if (k === 'AND' || k === 'OR' || k === 'NOT') {
if (Array.isArray(v)) {
out[k] = v.map(item => _processWhereFilters(item as Record<string, unknown>, fieldToDb));
} else if (v && typeof v === 'object') {
out[k] = _processWhereFilters(v as Record<string, unknown>, fieldToDb);
} else {
out[k] = v;
}
} else {
const dbKey = fieldToDb[k] ?? k;
if (v && typeof v === 'object' && !Array.isArray(v)) {
const ops: Record<string, unknown> = {};
for (const [op, opVal] of Object.entries(v as Record<string, unknown>)) {
const actualOp = op === 'isNull' ? 'isNull' : op;
if (actualOp === 'equals') {
out[dbKey] = opVal;
} else {
ops[actualOp] = opVal;
}
}
if (Object.keys(ops).length > 0) out[dbKey] = ops;
} else {
out[dbKey] = v;
}
}
}
return out;
}
function _processCreateData(
data: Record<string, unknown>,
fieldToDb: Record<string, string>,
): Record<string, unknown> {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(data)) {
const dbKey = fieldToDb[k] ?? k;
// Coerce Date -> ISO string for the engine.
out[dbKey] = v instanceof Date ? v.toISOString() : v;
}
return out;
}
function _serializeInclude(include: unknown): unknown {
if (include == null || typeof include === 'boolean') return include;
if (typeof include !== 'object' || Array.isArray(include)) return include;
const result: Record<string, unknown> = {};
for (const [field, spec] of Object.entries(include as Record<string, unknown>)) {
if (typeof spec === 'boolean') {
result[field] = spec;
} else if (spec && typeof spec === 'object') {
result[field] = _serializeInclude(spec);
} else {
result[field] = spec;
}
}
return result;
}
export class {{ delegate_name }} {
constructor(public client: NautilusClient) {}
async findMany(args?: {
where?: {{ model_name }}WhereInput;
orderBy?: {{ model_name }}OrderByInput | {{ model_name }}OrderByInput[];
take?: number;
skip?: number;
select?: {{ model_name }}SelectInput;
include?: {% if has_includes %}{{ model_name }}IncludeInput{% else %}Record<string, unknown>{% endif %};
cursor?: Record<string, unknown>;
distinct?: string[];
chunkSize?: number;
}): Promise<{{ model_name }}Model[]> {
const rpcArgs: Record<string, unknown> = {};
if (args?.where != null) rpcArgs['where'] = _processWhereFilters(args.where as Record<string, unknown>, _{{ table_name }}FieldToDb);
if (args?.orderBy != null) {
const ob = args.orderBy;
rpcArgs['orderBy'] = Array.isArray(ob) ? ob : [ob];
}
if (args?.take != null) rpcArgs['take'] = args.take;
if (args?.skip != null) rpcArgs['skip'] = args.skip;
if (args?.select != null) rpcArgs['select'] = args.select;
if (args?.include != null) rpcArgs['include'] = _serializeInclude(args.include);
if (args?.cursor != null) rpcArgs['cursor'] = args.cursor;
if (args?.distinct != null) rpcArgs['distinct'] = args.distinct;
const request: Record<string, unknown> = {
protocolVersion: 1,
model: '{{ model_name }}',
args: rpcArgs,
};
if (args?.chunkSize != null) request['chunkSize'] = args.chunkSize;
const result = (await this.client._rpc('query.findMany', request)) as Record<string, unknown>;
return ((result['data'] as unknown[]) ?? []).map(r => _coerce{{ model_name }}(r as Record<string, unknown>));
}
async findFirst(args?: {
where?: {{ model_name }}WhereInput;
orderBy?: {{ model_name }}OrderByInput | {{ model_name }}OrderByInput[];
select?: {{ model_name }}SelectInput;
include?: {% if has_includes %}{{ model_name }}IncludeInput{% else %}Record<string, unknown>{% endif %};
}): Promise<{{ model_name }}Model | null> {
const rows = await this.findMany({ where: args?.where, orderBy: args?.orderBy, take: 1, select: args?.select, include: args?.include });
return rows[0] ?? null;
}
async findUnique(args: {
where: {{ model_name }}WhereInput;
select?: {{ model_name }}SelectInput;
include?: {% if has_includes %}{{ model_name }}IncludeInput{% else %}Record<string, unknown>{% endif %};
}): Promise<{{ model_name }}Model | null> {
const rows = await this.findMany({ where: args.where, take: 1, select: args.select, include: args.include });
return rows[0] ?? null;
}
async findUniqueOrThrow(args: {
where: {{ model_name }}WhereInput;
select?: {{ model_name }}SelectInput;
include?: {% if has_includes %}{{ model_name }}IncludeInput{% else %}Record<string, unknown>{% endif %};
}): Promise<{{ model_name }}Model> {
const record = await this.findUnique(args);
if (record == null) throw new NotFoundError('findUniqueOrThrow: no {{ model_name }} record found matching the given filter');
return record;
}
async findFirstOrThrow(args?: {
where?: {{ model_name }}WhereInput;
orderBy?: {{ model_name }}OrderByInput | {{ model_name }}OrderByInput[];
select?: {{ model_name }}SelectInput;
include?: {% if has_includes %}{{ model_name }}IncludeInput{% else %}Record<string, unknown>{% endif %};
}): Promise<{{ model_name }}Model> {
const record = await this.findFirst(args);
if (record == null) throw new NotFoundError('findFirstOrThrow: no {{ model_name }} record found matching the given filter');
return record;
}
async create(args: {
data: {{ model_name }}CreateInput;
returnData?: boolean;
}): Promise<{{ model_name }}Model | null> {
{%- if updated_at_fields | length > 0 %}
const _createData: Record<string, unknown> = { ...(args.data as Record<string, unknown>) };
{%- for field in updated_at_fields %}
if (!('{{ field }}' in _createData) || _createData['{{ field }}'] == null) _createData['{{ field }}'] = new Date();
{%- endfor %}
{%- endif %}
const result = (await this.client._rpc('query.create', {
protocolVersion: 1,
model: '{{ model_name }}',
data: _processCreateData({% if updated_at_fields | length > 0 %}_createData{% else %}args.data as Record<string, unknown>{% endif %}, _{{ table_name }}FieldToDb),
returnData: args.returnData ?? true,
})) as Record<string, unknown>;
if (!(args.returnData ?? true)) return null;
const rows = result['data'] as unknown[] | undefined;
if (!rows?.length) throw new Error('create: engine returned no data');
return _coerce{{ model_name }}(rows[0] as Record<string, unknown>);
}
async createMany(args: {
data: {{ model_name }}CreateInput[];
returnData?: boolean;
}): Promise<{{ model_name }}Model[]> {
{%- if updated_at_fields | length > 0 %}
const _batchData = args.data.map(d => {
const _d: Record<string, unknown> = { ...(d as Record<string, unknown>) };
{%- for field in updated_at_fields %}
if (!('{{ field }}' in _d) || _d['{{ field }}'] == null) _d['{{ field }}'] = new Date();
{%- endfor %}
return _d;
});
{%- endif %}
const result = (await this.client._rpc('query.createMany', {
protocolVersion: 1,
model: '{{ model_name }}',
data: {% if updated_at_fields | length > 0 %}_batchData.map(d => _processCreateData(d, _{{ table_name }}FieldToDb)){% else %}args.data.map(d => _processCreateData(d as Record<string, unknown>, _{{ table_name }}FieldToDb)){% endif %},
returnData: args.returnData ?? true,
})) as Record<string, unknown>;
if (!(args.returnData ?? true)) return [];
return ((result['data'] as unknown[]) ?? []).map(r => _coerce{{ model_name }}(r as Record<string, unknown>));
}
async update(args: {
where?: {{ model_name }}WhereInput;
data: {{ model_name }}UpdateInput;
returnData?: boolean;
}): Promise<{{ model_name }}Model[] | number> {
{%- if updated_at_fields | length > 0 %}
const _updateData: Record<string, unknown> = { ...(args.data as Record<string, unknown>) };
{%- for field in updated_at_fields %}
if (!('{{ field }}' in _updateData) || _updateData['{{ field }}'] == null) _updateData['{{ field }}'] = new Date();
{%- endfor %}
{%- endif %}
const result = (await this.client._rpc('query.update', {
protocolVersion: 1,
model: '{{ model_name }}',
filter: _processWhereFilters((args.where ?? {}) as Record<string, unknown>, _{{ table_name }}FieldToDb),
data: _processCreateData({% if updated_at_fields | length > 0 %}_updateData{% else %}args.data as Record<string, unknown>{% endif %}, _{{ table_name }}FieldToDb),
returnData: args.returnData ?? true,
})) as Record<string, unknown>;
if (!(args.returnData ?? true)) return (result['count'] as number) ?? 0;
return ((result['data'] as unknown[]) ?? []).map(r => _coerce{{ model_name }}(r as Record<string, unknown>));
}
async delete(args: {
where: {{ model_name }}WhereInput;
returnData?: boolean;
}): Promise<{{ model_name }}Model | null> {
const record = await this.findFirst({ where: args.where });
if (record == null) throw new NotFoundError('delete: no {{ model_name }} record found matching the given filter');
const pkFilter: Record<string, unknown> = {
{%- for pk in primary_key_fields %}
'{{ pk }}': (record as Record<string, unknown>)['{{ pk }}'],
{%- endfor %}
};
const result = (await this.client._rpc('query.delete', {
protocolVersion: 1,
model: '{{ model_name }}',
filter: _processWhereFilters(pkFilter, _{{ table_name }}FieldToDb),
returnData: args.returnData ?? true,
})) as Record<string, unknown>;
if (!(args.returnData ?? true)) return null;
const rows = result['data'] as unknown[] | undefined;
return rows?.length ? _coerce{{ model_name }}(rows[0] as Record<string, unknown>) : record;
}
async deleteMany(args?: {
where?: {{ model_name }}WhereInput;
returnData?: boolean;
}): Promise<{{ model_name }}Model[] | number> {
const returnData = args?.returnData ?? false;
const result = (await this.client._rpc('query.delete', {
protocolVersion: 1,
model: '{{ model_name }}',
filter: _processWhereFilters((args?.where ?? {}) as Record<string, unknown>, _{{ table_name }}FieldToDb),
returnData,
})) as Record<string, unknown>;
if (returnData) return ((result['data'] as unknown[]) ?? []).map(r => _coerce{{ model_name }}(r as Record<string, unknown>));
return (result['count'] as number) ?? 0;
}
async count(args?: {
where?: {{ model_name }}WhereInput;
take?: number;
skip?: number;
cursor?: Record<string, unknown>;
}): Promise<number> {
const rpcArgs: Record<string, unknown> = {};
if (args?.where != null) rpcArgs['where'] = _processWhereFilters(args.where as Record<string, unknown>, _{{ table_name }}FieldToDb);
if (args?.take != null) rpcArgs['take'] = args.take;
if (args?.skip != null) rpcArgs['skip'] = args.skip;
if (args?.cursor != null) rpcArgs['cursor'] = args.cursor;
const result = (await this.client._rpc('query.count', {
protocolVersion: 1,
model: '{{ model_name }}',
args: Object.keys(rpcArgs).length ? rpcArgs : null,
})) as Record<string, unknown>;
return (result['count'] as number) ?? 0;
}
/**
* Execute a raw SQL string and return the result rows as generic objects.
*
* The SQL is sent to the database as-is with no parameter binding.
* Prefer {@link rawStmtQuery} when user-supplied values are involved to
* avoid SQL injection.
*/
async rawQuery(sql: string): Promise<Record<string, unknown>[]> {
const result = (await this.client._rpc('query.rawQuery', {
protocolVersion: 1,
sql,
})) as Record<string, unknown>;
return (result['data'] as Record<string, unknown>[]) ?? [];
}
/**
* Execute a raw prepared-statement query with bound parameters.
*
* Use `$1`, `$2`, … (PostgreSQL) or `?` (MySQL / SQLite) as placeholders.
* Parameters are bound in the order they appear in the `params` array.
*/
async rawStmtQuery(sql: string, params?: unknown[]): Promise<Record<string, unknown>[]> {
const result = (await this.client._rpc('query.rawStmtQuery', {
protocolVersion: 1,
sql,
params: params ?? [],
})) as Record<string, unknown>;
return (result['data'] as Record<string, unknown>[]) ?? [];
}
async upsert(args: {
where: {{ model_name }}WhereInput;
data: {{ model_name }}UpsertInput;
include?: {% if has_includes %}{{ model_name }}IncludeInput{% else %}Record<string, unknown>{% endif %};
returnData?: boolean;
}): Promise<{{ model_name }}Model | null> {
const existing = await this.findFirst({ where: args.where });
if (existing != null) {
const updated = await this.update({ where: args.where, data: args.data.update, returnData: args.returnData ?? true });
if (!(args.returnData ?? true)) return null;
if (args.include) {
const rows = await this.findMany({ where: args.where, take: 1, include: args.include });
return rows[0] ?? (Array.isArray(updated) ? updated[0] : null) ?? existing;
}
return Array.isArray(updated) ? (updated[0] ?? existing) : existing;
}
const created = await this.create({ data: args.data.create, returnData: args.returnData ?? true });
if (!(args.returnData ?? true)) return null;
if (created == null) throw new Error('upsert: create returned no data');
if (args.include) {
const rows = await this.findMany({ where: args.where, take: 1, include: args.include });
return rows[0] ?? created;
}
return created;
}
async groupBy(args: {
by: {{ model_name }}ScalarFieldKeys[];
where?: {{ model_name }}WhereInput;
having?: Record<string, unknown>;
take?: number;
skip?: number;
count?: boolean | {{ model_name }}CountAggregateInput;
{%- if has_numeric_fields %}
avg?: {{ model_name }}AvgAggregateInput;
sum?: {{ model_name }}SumAggregateInput;
{%- endif %}
min?: {{ model_name }}MinAggregateInput;
max?: {{ model_name }}MaxAggregateInput;
order?: Record<string, SortOrder> | Record<string, SortOrder>[];
}): Promise<{{ model_name }}GroupByOutput[]> {
const rpcArgs: Record<string, unknown> = { by: [...args.by] };
if (args.where != null) rpcArgs['where'] = _processWhereFilters(args.where as Record<string, unknown>, _{{ table_name }}FieldToDb);
if (args.having != null) rpcArgs['having'] = args.having;
if (args.take != null) rpcArgs['take'] = args.take;
if (args.skip != null) rpcArgs['skip'] = args.skip;
if (args.count != null) rpcArgs['count'] = args.count;
{%- if has_numeric_fields %}
if (args.avg != null) rpcArgs['avg'] = args.avg;
if (args.sum != null) rpcArgs['sum'] = args.sum;
{%- endif %}
if (args.min != null) rpcArgs['min'] = args.min;
if (args.max != null) rpcArgs['max'] = args.max;
if (args.order != null) {
const o = args.order;
rpcArgs['orderBy'] = Array.isArray(o) ? o : [o];
}
const result = (await this.client._rpc('query.groupBy', {
protocolVersion: 1,
model: '{{ model_name }}',
args: rpcArgs,
})) as Record<string, unknown>;
return (result['data'] as {{ model_name }}GroupByOutput[]) ?? [];
}
}
export type { NautilusClient };