mirror of
https://github.com/matrix-construct/construct
synced 2024-11-18 16:00:57 +01:00
441 lines
7.9 KiB
C++
441 lines
7.9 KiB
C++
// Matrix Construct
|
|
//
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
// full license for this software is available in the LICENSE file.
|
|
|
|
//
|
|
// seek
|
|
//
|
|
|
|
void
|
|
ircd::m::seek(event::fetch &fetch,
|
|
const event::id &event_id)
|
|
{
|
|
if(!seek(std::nothrow, fetch, event_id))
|
|
throw m::NOT_FOUND
|
|
{
|
|
"%s not found in database",
|
|
event_id
|
|
};
|
|
}
|
|
|
|
bool
|
|
ircd::m::seek(std::nothrow_t,
|
|
event::fetch &fetch,
|
|
const event::id &event_id)
|
|
{
|
|
const auto &event_idx
|
|
{
|
|
index(std::nothrow, event_id)
|
|
};
|
|
|
|
return seek(std::nothrow, fetch, event_idx, event_id);
|
|
}
|
|
|
|
void
|
|
ircd::m::seek(event::fetch &fetch,
|
|
const event::idx &event_idx)
|
|
{
|
|
if(!seek(std::nothrow, fetch, event_idx))
|
|
throw m::NOT_FOUND
|
|
{
|
|
"%lu not found in database",
|
|
event_idx
|
|
};
|
|
}
|
|
|
|
bool
|
|
ircd::m::seek(std::nothrow_t,
|
|
event::fetch &fetch,
|
|
const event::idx &event_idx)
|
|
{
|
|
return seek(std::nothrow, fetch, event_idx, m::event::id{});
|
|
}
|
|
|
|
bool
|
|
ircd::m::seek(std::nothrow_t,
|
|
event::fetch &fetch,
|
|
const event::idx &event_idx,
|
|
const event::id &event_id)
|
|
{
|
|
fetch.event_idx = event_idx;
|
|
fetch.event_id_buf = event_id?
|
|
event::id::buf{event_id}:
|
|
event::id::buf{};
|
|
|
|
if(!event_idx)
|
|
{
|
|
fetch.valid = false;
|
|
return fetch.valid;
|
|
}
|
|
|
|
const string_view &key
|
|
{
|
|
byte_view<string_view>(event_idx)
|
|
};
|
|
|
|
auto &event
|
|
{
|
|
static_cast<m::event &>(fetch)
|
|
};
|
|
|
|
assert(fetch.fopts);
|
|
const auto &opts(*fetch.fopts);
|
|
if(!fetch.should_seek_json(opts))
|
|
if((fetch.valid = db::seek(fetch.row, key, opts.gopts)))
|
|
if((fetch.valid = fetch.assign_from_row(key)))
|
|
return fetch.valid;
|
|
|
|
if((fetch.valid = fetch._json.load(key, opts.gopts)))
|
|
fetch.valid = fetch.assign_from_json(key);
|
|
|
|
return fetch.valid;
|
|
}
|
|
|
|
//
|
|
// event::fetch
|
|
//
|
|
|
|
decltype(ircd::m::event::fetch::default_opts)
|
|
ircd::m::event::fetch::default_opts
|
|
{};
|
|
|
|
//
|
|
// event::fetch::fetch
|
|
//
|
|
|
|
/// Seek to event_id and populate this event from database.
|
|
/// Throws if event not in database.
|
|
ircd::m::event::fetch::fetch(const event::id &event_id,
|
|
const opts &opts)
|
|
:fetch
|
|
{
|
|
std::nothrow,
|
|
index(event_id),
|
|
event_id,
|
|
opts,
|
|
}
|
|
{
|
|
if(!valid)
|
|
throw m::NOT_FOUND
|
|
{
|
|
"%s not found in database",
|
|
string_view{event_id}
|
|
};
|
|
}
|
|
|
|
/// Seek to event_id and populate this event from database.
|
|
/// Event is not populated if not found in database.
|
|
ircd::m::event::fetch::fetch(std::nothrow_t,
|
|
const event::id &event_id,
|
|
const opts &opts)
|
|
:fetch
|
|
{
|
|
std::nothrow,
|
|
index(std::nothrow, event_id),
|
|
event_id,
|
|
opts,
|
|
}
|
|
{
|
|
}
|
|
|
|
/// Seek to event_idx and populate this event from database.
|
|
/// Throws if event not in database.
|
|
ircd::m::event::fetch::fetch(const event::idx &event_idx,
|
|
const opts &opts)
|
|
:fetch
|
|
{
|
|
std::nothrow,
|
|
event_idx,
|
|
opts,
|
|
}
|
|
{
|
|
if(!valid)
|
|
throw m::NOT_FOUND
|
|
{
|
|
"idx %zu not found in database",
|
|
event_idx
|
|
};
|
|
}
|
|
|
|
ircd::m::event::fetch::fetch(std::nothrow_t,
|
|
const event::idx &event_idx,
|
|
const opts &opts)
|
|
:fetch
|
|
{
|
|
std::nothrow,
|
|
event_idx,
|
|
m::event::id{},
|
|
opts,
|
|
}
|
|
{
|
|
}
|
|
|
|
/// Seek to event_idx and populate this event from database.
|
|
/// Event is not populated if not found in database.
|
|
ircd::m::event::fetch::fetch(std::nothrow_t,
|
|
const event::idx &event_idx,
|
|
const event::id &event_id,
|
|
const opts &opts)
|
|
:fopts
|
|
{
|
|
&opts
|
|
}
|
|
,event_idx
|
|
{
|
|
event_idx
|
|
}
|
|
,_json
|
|
{
|
|
dbs::event_json,
|
|
event_idx && should_seek_json(opts)?
|
|
key(&event_idx):
|
|
string_view{},
|
|
opts.gopts
|
|
}
|
|
,row
|
|
{
|
|
*dbs::events,
|
|
event_idx && !_json.valid(key(&event_idx))?
|
|
key(&event_idx):
|
|
string_view{},
|
|
event_idx && !_json.valid(key(&event_idx))?
|
|
event::keys{opts.keys}:
|
|
event::keys{event::keys::include{}},
|
|
cell,
|
|
opts.gopts
|
|
}
|
|
,valid
|
|
{
|
|
false
|
|
}
|
|
,event_id_buf
|
|
{
|
|
event_id?
|
|
event::id::buf{event_id}:
|
|
event::id::buf{}
|
|
}
|
|
{
|
|
valid =
|
|
event_idx && _json.valid(key(&event_idx))?
|
|
assign_from_json(key(&event_idx)):
|
|
event_idx?
|
|
assign_from_row(key(&event_idx)):
|
|
false;
|
|
}
|
|
|
|
/// Seekless constructor.
|
|
ircd::m::event::fetch::fetch(const opts &opts)
|
|
:fopts
|
|
{
|
|
&opts
|
|
}
|
|
,_json
|
|
{
|
|
dbs::event_json,
|
|
string_view{},
|
|
opts.gopts
|
|
}
|
|
,row
|
|
{
|
|
*dbs::events,
|
|
string_view{},
|
|
!should_seek_json(opts)?
|
|
event::keys{opts.keys}:
|
|
event::keys{event::keys::include{}},
|
|
cell,
|
|
opts.gopts
|
|
}
|
|
,valid
|
|
{
|
|
false
|
|
}
|
|
{
|
|
}
|
|
|
|
// array of db::cell::~cell()
|
|
ircd::m::event::fetch::~fetch()
|
|
noexcept
|
|
{
|
|
}
|
|
|
|
[[gnu::visibility("hidden")]]
|
|
bool
|
|
ircd::m::event::fetch::assign_from_json(const string_view &key)
|
|
try
|
|
{
|
|
auto &event
|
|
{
|
|
static_cast<m::event &>(*this)
|
|
};
|
|
|
|
assert(_json.valid(key));
|
|
const json::object source
|
|
{
|
|
_json.val()
|
|
};
|
|
|
|
assert(!empty(source));
|
|
const bool source_event_id
|
|
{
|
|
!event_id_buf && source.has("event_id")
|
|
};
|
|
|
|
const auto event_id
|
|
{
|
|
source_event_id?
|
|
id(json::string(source.at("event_id"))):
|
|
event_id_buf?
|
|
id(event_id_buf):
|
|
m::event_id(std::nothrow, event_idx, event_id_buf)
|
|
};
|
|
|
|
assert(fopts);
|
|
assert(event_id);
|
|
event =
|
|
{
|
|
source, event_id, event::keys{fopts->keys}
|
|
};
|
|
|
|
assert(data(event.source) == data(source));
|
|
assert(event.event_id == event_id);
|
|
return true;
|
|
}
|
|
catch(const json::parse_error &e)
|
|
{
|
|
const ctx::exception_handler eh;
|
|
|
|
const auto event_id
|
|
{
|
|
event_id_buf?
|
|
id(event_id_buf):
|
|
m::event_id(std::nothrow, event_idx, event_id_buf)
|
|
};
|
|
|
|
log::critical
|
|
{
|
|
m::log, "Fetching event:%lu %s JSON from local database :%s",
|
|
event_idx,
|
|
string_view{event_id},
|
|
e.what(),
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
[[gnu::visibility("hidden")]]
|
|
bool
|
|
ircd::m::event::fetch::assign_from_row(const string_view &key)
|
|
try
|
|
{
|
|
auto &event
|
|
{
|
|
static_cast<m::event &>(*this)
|
|
};
|
|
|
|
if(!row.valid(key))
|
|
return false;
|
|
|
|
event.source = {};
|
|
assign(event, row, key);
|
|
|
|
// N.B. a row assignment might not produce an event.event_id unless
|
|
// the key is explicitly selected or it was otherwise trivially found.
|
|
event.event_id =
|
|
{
|
|
event.event_id?
|
|
event.event_id:
|
|
|
|
!empty(json::get<"event_id"_>(event))?
|
|
event::id{json::get<"event_id"_>(event)}:
|
|
|
|
event_id_buf?
|
|
event::id{event_id_buf}:
|
|
|
|
cell.at(json::indexof<m::event, "event_id"_>())?
|
|
event::id{cell.at(json::indexof<m::event, "event_id"_>()).val()}:
|
|
|
|
event::id{}
|
|
};
|
|
|
|
return true;
|
|
}
|
|
catch(const json::parse_error &e)
|
|
{
|
|
const ctx::exception_handler eh;
|
|
|
|
const auto event_id
|
|
{
|
|
event_id_buf?
|
|
id(event_id_buf):
|
|
m::event_id(std::nothrow, event_idx, event_id_buf)
|
|
};
|
|
|
|
log::critical
|
|
{
|
|
m::log, "Fetching event:%lu %s JSON from local database :%s",
|
|
event_idx,
|
|
string_view{event_id},
|
|
e.what(),
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
[[gnu::visibility("hidden")]]
|
|
bool
|
|
ircd::m::event::fetch::should_seek_json(const opts &opts)
|
|
{
|
|
// User always wants to make the event_json query regardless
|
|
// of their keys selection.
|
|
if(opts.query_json_force)
|
|
return true;
|
|
|
|
// If and only if selected keys have direct columns we can return
|
|
// false to seek direct columns. If any other keys are selected we
|
|
/// must perform the event_json query instead.
|
|
for(size_t i(0); i < opts.keys.size(); ++i)
|
|
if(opts.keys.test(i))
|
|
if(!dbs::event_column.at(i))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
[[gnu::visibility("hidden")]]
|
|
ircd::string_view
|
|
ircd::m::event::fetch::key(const event::idx *const &event_idx)
|
|
{
|
|
assert(event_idx);
|
|
return byte_view<string_view>(*event_idx);
|
|
}
|
|
|
|
//
|
|
// event::fetch::opts
|
|
//
|
|
|
|
ircd::m::event::fetch::opts::opts(const db::gopts &gopts,
|
|
const event::keys::selection &keys)
|
|
:opts
|
|
{
|
|
keys, gopts
|
|
}
|
|
{
|
|
}
|
|
|
|
ircd::m::event::fetch::opts::opts(const event::keys::selection &keys,
|
|
const db::gopts &gopts)
|
|
:keys{keys}
|
|
,gopts{gopts}
|
|
{
|
|
}
|
|
|
|
ircd::m::event::fetch::opts::opts()
|
|
noexcept
|
|
{
|
|
}
|