feat: add save and has to index
This commit is contained in:
1 parent
51cf300adb
commit
43b27efecc
1 file changed
+161
+161
@@ -473,3 +473,164 @@ pub const ForeignKeySet = struct {
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save(self: *const ForeignKeySet, db: *Db, table: []const u8) !void {
|
||||||
|
const key = try foreignKeyMetaKey(self.allocator, table);
|
||||||
|
defer self.allocator.free(key);
|
||||||
|
|
||||||
|
var out = std.ArrayList(u8).init(self.allocator);
|
||||||
|
defer out.deinit();
|
||||||
|
var countBuf: [4]u8 = undefined;
|
||||||
|
std.mem.writeInt(u32, &countBuf, @intCast(self.specs.items.len), .little);
|
||||||
|
try out.appendSlice(&countBuf);
|
||||||
|
for (self.specs.items) |spec| {
|
||||||
|
try appendLenPrefixed(&out, spec.field);
|
||||||
|
try appendLenPrefixed(&out, spec.refTable);
|
||||||
|
try appendLenPrefixed(&out, spec.refField);
|
||||||
|
try out.append(@intFromEnum(spec.onDelete));
|
||||||
|
}
|
||||||
|
try db.put(key, out.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has(self: *const ForeignKeySet, field: []const u8) bool {
|
||||||
|
return self.find(field) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(self: *const ForeignKeySet, field: []const u8) ?ForeignKeySpec {
|
||||||
|
for (self.specs.items) |spec| {
|
||||||
|
if (std.mem.eql(u8, spec.field, field)) return spec;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(self: *ForeignKeySet, field: []const u8, refTable: []const u8, refField: []const u8, onDelete: OnDelete) !void {
|
||||||
|
if (self.has(field)) return;
|
||||||
|
const spec = ForeignKeySpec{
|
||||||
|
.field = try self.allocator.dupe(u8, field),
|
||||||
|
.refTable = try self.allocator.dupe(u8, refTable),
|
||||||
|
.refField = try self.allocator.dupe(u8, refField),
|
||||||
|
.onDelete = onDelete,
|
||||||
|
};
|
||||||
|
try self.specs.append(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if a constraint on `field` was present and has been
|
||||||
|
/// removed.
|
||||||
|
pub fn remove(self: *ForeignKeySet, field: []const u8) bool {
|
||||||
|
for (self.specs.items, 0..) |spec, i| {
|
||||||
|
if (std.mem.eql(u8, spec.field, field)) {
|
||||||
|
self.allocator.free(spec.field);
|
||||||
|
self.allocator.free(spec.refTable);
|
||||||
|
self.allocator.free(spec.refField);
|
||||||
|
_ = self.specs.orderedRemove(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ForeignKeySet) void {
|
||||||
|
for (self.specs.items) |spec| {
|
||||||
|
self.allocator.free(spec.field);
|
||||||
|
self.allocator.free(spec.refTable);
|
||||||
|
self.allocator.free(spec.refField);
|
||||||
|
}
|
||||||
|
self.specs.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// One named CHECK constraint: a caller-chosen `name` (used only as the key
|
||||||
|
/// under which the constraint can be dropped again, not part of the
|
||||||
|
/// keyspace layout - unlike `CompositeIndexSpec.name`, no index entries are
|
||||||
|
/// ever written for a CHECK) paired with the raw `expr.zig` predicate source
|
||||||
|
/// text it must evaluate true against. Stored as source rather than a parsed
|
||||||
|
/// tree because `index.zig` sits below `query.zig`/`expr.zig` in the
|
||||||
|
/// dependency graph and knows nothing about `Predicate` - parsing happens
|
||||||
|
/// fresh in whichever layer enforces it (`query.zig`'s `Table.put`,
|
||||||
|
/// `txn_table.zig`'s `TableTxn.put`), the same "reparse on every use" cost
|
||||||
|
/// `table select`/`table join` already pay for their own expr text.
|
||||||
|
pub const CheckConstraintSpec = struct {
|
||||||
|
name: []u8,
|
||||||
|
source: []u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Persisted set of CHECK constraints on a table, at most one per name -
|
||||||
|
/// same on-disk shape family as `ForeignKeySet` (own meta key, own
|
||||||
|
/// namespace, two length-prefixed strings per entry).
|
||||||
|
pub const CheckConstraintSet = struct {
|
||||||
|
allocator: Allocator,
|
||||||
|
specs: std.ArrayList(CheckConstraintSpec),
|
||||||
|
|
||||||
|
pub fn load(allocator: Allocator, db: *Db, table: []const u8) !CheckConstraintSet {
|
||||||
|
const key = try checkMetaKey(allocator, table);
|
||||||
|
defer allocator.free(key);
|
||||||
|
|
||||||
|
var set = CheckConstraintSet{ .allocator = allocator, .specs = std.ArrayList(CheckConstraintSpec).init(allocator) };
|
||||||
|
errdefer set.deinit();
|
||||||
|
|
||||||
|
const raw = try db.get(allocator, key) orelse return set;
|
||||||
|
defer allocator.free(raw);
|
||||||
|
|
||||||
|
var pos: usize = 0;
|
||||||
|
if (pos + 4 > raw.len) return error.Malformed;
|
||||||
|
const count = std.mem.readInt(u32, raw[pos..][0..4], .little);
|
||||||
|
pos += 4;
|
||||||
|
var i: u32 = 0;
|
||||||
|
while (i < count) : (i += 1) {
|
||||||
|
const name = try readLenPrefixed(allocator, raw, &pos);
|
||||||
|
errdefer allocator.free(name);
|
||||||
|
const source = try readLenPrefixed(allocator, raw, &pos);
|
||||||
|
try set.specs.append(.{ .name = name, .source = source });
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(self: *const CheckConstraintSet, db: *Db, table: []const u8) !void {
|
||||||
|
const key = try checkMetaKey(self.allocator, table);
|
||||||
|
defer self.allocator.free(key);
|
||||||
|
|
||||||
|
var out = std.ArrayList(u8).init(self.allocator);
|
||||||
|
defer out.deinit();
|
||||||
|
var countBuf: [4]u8 = undefined;
|
||||||
|
std.mem.writeInt(u32, &countBuf, @intCast(self.specs.items.len), .little);
|
||||||
|
try out.appendSlice(&countBuf);
|
||||||
|
for (self.specs.items) |spec| {
|
||||||
|
try appendLenPrefixed(&out, spec.name);
|
||||||
|
try appendLenPrefixed(&out, spec.source);
|
||||||
|
}
|
||||||
|
try db.put(key, out.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has(self: *const CheckConstraintSet, name: []const u8) bool {
|
||||||
|
return self.find(name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(self: *const CheckConstraintSet, name: []const u8) ?CheckConstraintSpec {
|
||||||
|
for (self.specs.items) |spec| {
|
||||||
|
if (std.mem.eql(u8, spec.name, name)) return spec;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(self: *CheckConstraintSet, name: []const u8, source: []const u8) !void {
|
||||||
|
if (self.has(name)) return;
|
||||||
|
const spec = CheckConstraintSpec{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.source = try self.allocator.dupe(u8, source),
|
||||||
|
};
|
||||||
|
try self.specs.append(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if a constraint named `name` was present and has been
|
||||||
|
/// removed.
|
||||||
|
pub fn remove(self: *CheckConstraintSet, name: []const u8) bool {
|
||||||
|
for (self.specs.items, 0..) |spec, i| {
|
||||||
|
if (std.mem.eql(u8, spec.name, name)) {
|
||||||
|
self.allocator.free(spec.name);
|
||||||
|
self.allocator.free(spec.source);
|
||||||
|
_ = self.specs.orderedRemove(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user