ZipponDB/src/ziql/parts/value.zig

290 lines
13 KiB
Zig

const std = @import("std");
const dtype = @import("dtype");
const UUID = dtype.UUID;
const Allocator = std.mem.Allocator;
const Token = @import("../tokenizer.zig").Token;
const Filter = @import("../../dataStructure/filter.zig").Filter;
const ConditionValue = @import("../../dataStructure/filter.zig").ConditionValue;
const AdditionalData = @import("../../dataStructure/additionalData.zig").AdditionalData;
const printError = @import("../../utils.zig").printError;
const ZipponError = @import("error").ZipponError;
const Self = @import("../parser.zig");
/// To run just after a condition like = or > or >= to get the corresponding ConditionValue that you need to compare
pub fn parseConditionValue(self: Self, allocator: Allocator, struct_name: []const u8, member_name: []const u8, data_type: dtype.DataType, token: *Token) ZipponError!ConditionValue {
const start_index = token.loc.start;
const expected_tag: ?Token.Tag = switch (data_type) {
.int => .int_literal,
.float => .float_literal,
.str => .string_literal,
.self => .uuid_literal,
.int_array => .int_literal,
.float_array => .float_literal,
.str_array => .string_literal,
.bool, .bool_array, .link, .link_array, .date, .time, .datetime, .date_array, .time_array, .datetime_array => null, // handle separately
};
// Check if the all next tokens are the right one
if (expected_tag) |tag| {
if (data_type.is_array()) {
token.* = try self.checkTokensInArray(tag);
} else {
if (token.tag != tag) {
return printError(
"Error: Wrong type", // TODO: Print the expected type
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
} else switch (data_type) {
.bool => if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) {
return printError(
"Error: Expected bool",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.bool_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .bool_literal_true and token.tag != .bool_literal_false) {
return printError(
"Error: Expected bool or ]",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.date => if (token.tag != .date_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected date",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.date_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .date_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected date",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.time => if (token.tag != .time_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected time",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.time_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .time_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected time",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.datetime => if (token.tag != .datetime_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected datetime",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
},
.datetime_array => {
token.* = self.toker.next();
while (token.tag != .r_bracket) : (token.* = self.toker.next()) {
if (token.tag != .datetime_literal and token.tag != .keyword_now) {
return printError(
"Error: Expected datetime",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
}
}
},
.link, .link_array => {},
else => unreachable,
}
// And finally create the ConditionValue
switch (data_type) {
.int => return ConditionValue.initInt(self.toker.buffer[start_index..token.loc.end]),
.float => return ConditionValue.initFloat(self.toker.buffer[start_index..token.loc.end]),
.str => return ConditionValue.initStr(self.toker.buffer[start_index + 1 .. token.loc.end - 1]),
.date => return ConditionValue.initDate(self.toker.buffer[start_index..token.loc.end]),
.time => return ConditionValue.initTime(self.toker.buffer[start_index..token.loc.end]),
.datetime => return ConditionValue.initDateTime(self.toker.buffer[start_index..token.loc.end]),
.bool => return ConditionValue.initBool(self.toker.buffer[start_index..token.loc.end]),
.int_array => return try ConditionValue.initArrayInt(allocator, self.toker.buffer[start_index..token.loc.end]),
.str_array => return try ConditionValue.initArrayStr(allocator, self.toker.buffer[start_index..token.loc.end]),
.bool_array => return try ConditionValue.initArrayBool(allocator, self.toker.buffer[start_index..token.loc.end]),
.float_array => return try ConditionValue.initArrayFloat(allocator, self.toker.buffer[start_index..token.loc.end]),
.date_array => return try ConditionValue.initArrayDate(allocator, self.toker.buffer[start_index..token.loc.end]),
.time_array => return try ConditionValue.initArrayTime(allocator, self.toker.buffer[start_index..token.loc.end]),
.datetime_array => return try ConditionValue.initArrayDateTime(allocator, self.toker.buffer[start_index..token.loc.end]),
.link => switch (token.tag) {
.keyword_none => { // TODO: Stop creating a map if empty, can be null or something. Or maybe just keep one map link that in memory, so I dont create it everytime
const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError;
map.* = std.AutoHashMap(UUID, void).init(allocator);
map.put(dtype.Zero, {}) catch return ZipponError.MemoryError;
_ = self.toker.next();
return ConditionValue.initLink(map);
},
.uuid_literal => {
const uuid = UUID.parse(self.toker.buffer[start_index..token.loc.end]) catch return ZipponError.InvalidUUID;
if (!self.schema_engine.isUUIDExist(struct_name, uuid)) return printError(
"Error: UUID do not exist in database.",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError;
map.* = std.AutoHashMap(UUID, void).init(allocator);
map.put(uuid, {}) catch return ZipponError.MemoryError;
_ = self.toker.next();
return ConditionValue.initLink(map);
},
.l_brace, .l_bracket => {
var filter: ?Filter = null;
defer if (filter != null) filter.?.deinit();
var additional_data_arena = std.heap.ArenaAllocator.init(allocator);
defer additional_data_arena.deinit();
var additional_data = AdditionalData.init(additional_data_arena.allocator());
if (token.tag == .l_bracket) {
try self.parseAdditionalData(allocator, &additional_data, struct_name);
token.* = self.toker.next();
}
additional_data.limit = 1;
const link_sstruct = try self.schema_engine.linkedStructName(struct_name, member_name);
if (token.tag == .l_brace) filter = try self.parseFilter(
allocator,
link_sstruct.name,
false,
) else return printError(
"Error: Expected filter",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
filter = switch (filter.?.root.*) {
.empty => null,
else => filter,
};
// Here I have the filter and additionalData
const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError;
map.* = std.AutoHashMap(UUID, void).init(allocator);
try self.file_engine.populateVoidUUIDMap(
link_sstruct.name,
filter,
map,
&additional_data,
);
return ConditionValue.initLink(map);
},
else => return printError(
"Error: Expected uuid or none",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.link_array => switch (token.tag) {
.keyword_none => {
const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError;
map.* = std.AutoHashMap(UUID, void).init(allocator);
_ = self.toker.next();
return ConditionValue.initArrayLink(map);
},
.l_brace, .l_bracket => {
var filter: ?Filter = null;
defer if (filter != null) filter.?.deinit();
var additional_data_arena = std.heap.ArenaAllocator.init(allocator);
defer additional_data_arena.deinit();
var additional_data = AdditionalData.init(additional_data_arena.allocator());
if (token.tag == .l_bracket) {
try self.parseAdditionalData(allocator, &additional_data, struct_name);
token.* = self.toker.next();
}
const link_sstruct = try self.schema_engine.linkedStructName(struct_name, member_name);
if (token.tag == .l_brace) filter = try self.parseFilter(allocator, link_sstruct.name, false) else return printError(
"Error: Expected filter",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
);
filter = switch (filter.?.root.*) {
.empty => null,
else => filter,
};
// Here I have the filter and additionalData
const map = allocator.create(std.AutoHashMap(UUID, void)) catch return ZipponError.MemoryError;
map.* = std.AutoHashMap(UUID, void).init(allocator);
try self.file_engine.populateVoidUUIDMap(
struct_name,
filter,
map,
&additional_data,
);
return ConditionValue.initArrayLink(map);
},
else => return printError(
"Error: Expected uuid or none",
ZipponError.SynthaxError,
self.toker.buffer,
token.loc.start,
token.loc.end,
),
},
.self => unreachable,
}
}