Files
bun.sh/src/sql/postgres/protocol/NewReader.zig
Ciro Spaciari ecbf103bf5 feat(MYSQL) Bun.SQL mysql support (#21968)
### What does this PR do?
Add MySQL support, Refactor will be in a followup PR
### How did you verify your code works?
A lot of tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cirospaciari <6379399+cirospaciari@users.noreply.github.com>
2025-08-21 15:28:15 -07:00

121 lines
4.1 KiB
Zig

pub fn NewReaderWrap(
comptime Context: type,
comptime markMessageStartFn_: (fn (ctx: Context) void),
comptime peekFn_: (fn (ctx: Context) []const u8),
comptime skipFn_: (fn (ctx: Context, count: usize) void),
comptime ensureCapacityFn_: (fn (ctx: Context, count: usize) bool),
comptime readFunction_: (fn (ctx: Context, count: usize) AnyPostgresError!Data),
comptime readZ_: (fn (ctx: Context) AnyPostgresError!Data),
) type {
return struct {
wrapped: Context,
const readFn = readFunction_;
const readZFn = readZ_;
const ensureCapacityFn = ensureCapacityFn_;
const skipFn = skipFn_;
const peekFn = peekFn_;
const markMessageStartFn = markMessageStartFn_;
pub const Ctx = Context;
pub inline fn markMessageStart(this: @This()) void {
markMessageStartFn(this.wrapped);
}
pub inline fn read(this: @This(), count: usize) AnyPostgresError!Data {
return try readFn(this.wrapped, count);
}
pub inline fn eatMessage(this: @This(), comptime msg_: anytype) AnyPostgresError!void {
const msg = msg_[1..];
try this.ensureCapacity(msg.len);
var input = try readFn(this.wrapped, msg.len);
defer input.deinit();
if (bun.strings.eqlComptime(input.slice(), msg)) return;
return error.InvalidMessage;
}
pub fn skip(this: @This(), count: usize) AnyPostgresError!void {
skipFn(this.wrapped, count);
}
pub fn peek(this: @This()) []const u8 {
return peekFn(this.wrapped);
}
pub inline fn readZ(this: @This()) AnyPostgresError!Data {
return try readZFn(this.wrapped);
}
pub inline fn ensureCapacity(this: @This(), count: usize) AnyPostgresError!void {
if (!ensureCapacityFn(this.wrapped, count)) {
return error.ShortRead;
}
}
pub fn int(this: @This(), comptime Int: type) !Int {
var data = try this.read(@sizeOf((Int)));
defer data.deinit();
const slice = data.slice();
if (slice.len < @sizeOf(Int)) {
return error.ShortRead;
}
if (comptime Int == u8) {
return @as(Int, slice[0]);
}
return @byteSwap(@as(Int, @bitCast(slice[0..@sizeOf(Int)].*)));
}
pub fn peekInt(this: @This(), comptime Int: type) ?Int {
const remain = this.peek();
if (remain.len < @sizeOf(Int)) {
return null;
}
return @byteSwap(@as(Int, @bitCast(remain[0..@sizeOf(Int)].*)));
}
pub fn expectInt(this: @This(), comptime Int: type, comptime value: comptime_int) !bool {
const actual = try this.int(Int);
return actual == value;
}
pub fn int4(this: @This()) !PostgresInt32 {
return this.int(PostgresInt32);
}
pub fn short(this: @This()) !PostgresShort {
return this.int(PostgresShort);
}
pub fn length(this: @This()) !PostgresInt32 {
const expected = try this.int(PostgresInt32);
if (expected > -1) {
try this.ensureCapacity(@intCast(expected -| 4));
}
return expected;
}
pub const bytes = read;
pub fn String(this: @This()) !bun.String {
var result = try this.readZ();
defer result.deinit();
return bun.String.borrowUTF8(result.slice());
}
};
}
pub fn NewReader(comptime Context: type) type {
return NewReaderWrap(Context, Context.markMessageStart, Context.peek, Context.skip, Context.ensureLength, Context.read, Context.readZ);
}
const bun = @import("bun");
const AnyPostgresError = @import("../AnyPostgresError.zig").AnyPostgresError;
const Data = @import("../../shared/Data.zig").Data;
const int_types = @import("../types/int_types.zig");
const PostgresInt32 = int_types.PostgresInt32;
const PostgresShort = int_types.PostgresShort;