add user_id in revision

This commit is contained in:
appflowy 2021-12-09 22:28:11 +08:00
parent 3fa0f97e74
commit 45d9a0918f
19 changed files with 186 additions and 91 deletions

View File

@ -22,6 +22,7 @@ class Revision extends $pb.GeneratedMessage {
..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'md5')
..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
..e<RevType>(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: RevType.Local, valueOf: RevType.valueOf, enumValues: RevType.values)
..aOS(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'userId')
..hasRequiredFields = false
;
@ -33,6 +34,7 @@ class Revision extends $pb.GeneratedMessage {
$core.String? md5,
$core.String? docId,
RevType? ty,
$core.String? userId,
}) {
final _result = create();
if (baseRevId != null) {
@ -53,6 +55,9 @@ class Revision extends $pb.GeneratedMessage {
if (ty != null) {
_result.ty = ty;
}
if (userId != null) {
_result.userId = userId;
}
return _result;
}
factory Revision.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@ -129,6 +134,15 @@ class Revision extends $pb.GeneratedMessage {
$core.bool hasTy() => $_has(5);
@$pb.TagNumber(6)
void clearTy() => clearField(6);
@$pb.TagNumber(7)
$core.String get userId => $_getSZ(6);
@$pb.TagNumber(7)
set userId($core.String v) { $_setString(6, v); }
@$pb.TagNumber(7)
$core.bool hasUserId() => $_has(6);
@$pb.TagNumber(7)
void clearUserId() => clearField(7);
}
class RevId extends $pb.GeneratedMessage {

View File

@ -29,11 +29,12 @@ const Revision$json = const {
const {'1': 'md5', '3': 4, '4': 1, '5': 9, '10': 'md5'},
const {'1': 'doc_id', '3': 5, '4': 1, '5': 9, '10': 'docId'},
const {'1': 'ty', '3': 6, '4': 1, '5': 14, '6': '.RevType', '10': 'ty'},
const {'1': 'user_id', '3': 7, '4': 1, '5': 9, '10': 'userId'},
],
};
/// Descriptor for `Revision`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSHQoKZGVsdGFfZGF0YRgDIAEoDFIJZGVsdGFEYXRhEhAKA21kNRgEIAEoCVIDbWQ1EhUKBmRvY19pZBgFIAEoCVIFZG9jSWQSGAoCdHkYBiABKA4yCC5SZXZUeXBlUgJ0eQ==');
final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSHQoKZGVsdGFfZGF0YRgDIAEoDFIJZGVsdGFEYXRhEhAKA21kNRgEIAEoCVIDbWQ1EhUKBmRvY19pZBgFIAEoCVIFZG9jSWQSGAoCdHkYBiABKA4yCC5SZXZUeXBlUgJ0eRIXCgd1c2VyX2lkGAcgASgJUgZ1c2VySWQ=');
@$core.Deprecated('Use revIdDescriptor instead')
const RevId$json = const {
'1': 'RevId',

View File

@ -112,12 +112,13 @@ impl DocController {
// let doc = self.read_doc(doc_id, pool.clone()).await?;
let ws_sender = self.ws_manager.ws();
let token = self.user.token()?;
let user_id = self.user.user_id()?;
let server = Arc::new(RevisionServerImpl {
token,
server: self.server.clone(),
});
let cache = Arc::new(RevisionCache::new(doc_id, pool, server));
Ok(RevisionManager::new(doc_id, cache, ws_sender))
let cache = Arc::new(RevisionCache::new(&user_id, doc_id, pool, server));
Ok(RevisionManager::new(&user_id, doc_id, cache, ws_sender))
}
}

View File

@ -163,7 +163,8 @@ impl ClientDocEditor {
let delta_data = delta.to_bytes();
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id();
let delta_data = delta_data.to_vec();
let revision = Revision::new(base_rev_id, rev_id, delta_data, &self.doc_id, RevType::Local);
let user_id = self.user.user_id()?;
let revision = Revision::new(base_rev_id, rev_id, delta_data, &self.doc_id, RevType::Local, user_id);
let _ = self.rev_manager.add_revision(&revision).await?;
Ok(rev_id.into())
}
@ -236,22 +237,26 @@ impl ClientDocEditor {
let (local_base_rev_id, local_rev_id) = self.rev_manager.next_rev_id();
// save the revision
let user_id = self.user.user_id()?;
let revision = Revision::new(
local_base_rev_id,
local_rev_id,
client_prime.to_bytes().to_vec(),
&self.doc_id,
RevType::Remote,
user_id,
);
let _ = self.rev_manager.add_revision(&revision).await?;
// send the server_prime delta
let user_id = self.user.user_id()?;
let revision = Revision::new(
local_base_rev_id,
local_rev_id,
server_prime.to_bytes().to_vec(),
&self.doc_id,
RevType::Remote,
user_id,
);
let _ = self.ws_sender.send(revision.into());
Ok(())

View File

@ -24,6 +24,7 @@ pub trait RevisionIterator: Send + Sync {
type DocRevisionDeskCache = dyn RevisionDiskCache<Error = DocError>;
pub struct RevisionCache {
user_id: String,
doc_id: String,
dish_cache: Arc<DocRevisionDeskCache>,
memory_cache: Arc<RevisionMemoryCache>,
@ -32,11 +33,17 @@ pub struct RevisionCache {
}
impl RevisionCache {
pub fn new(doc_id: &str, pool: Arc<ConnectionPool>, server: Arc<dyn RevisionServer>) -> RevisionCache {
pub fn new(
user_id: &str,
doc_id: &str,
pool: Arc<ConnectionPool>,
server: Arc<dyn RevisionServer>,
) -> RevisionCache {
let doc_id = doc_id.to_owned();
let dish_cache = Arc::new(Persistence::new(pool));
let dish_cache = Arc::new(Persistence::new(user_id, pool));
let memory_cache = Arc::new(RevisionMemoryCache::new());
Self {
user_id: user_id.to_owned(),
doc_id,
dish_cache,
memory_cache,
@ -117,6 +124,7 @@ impl RevisionCache {
delta_data.to_owned(),
&doc.id,
RevType::Remote,
self.user_id.clone(),
);
let record = RevisionRecord {
revision,
@ -215,6 +223,7 @@ fn correct_delta_if_need(delta: &mut RichTextDelta) {
}
pub(crate) struct Persistence {
user_id: String,
pub(crate) pool: Arc<ConnectionPool>,
}
@ -231,25 +240,30 @@ impl RevisionDiskCache for Persistence {
fn revisions_in_range(&self, doc_id: &str, range: &RevisionRange) -> Result<Vec<Revision>, Self::Error> {
let conn = &*self.pool.get().map_err(internal_error).unwrap();
let revisions = RevTableSql::read_rev_tables_with_range(doc_id, range.clone(), conn)?;
let revisions = RevTableSql::read_rev_tables_with_range(&self.user_id, doc_id, range.clone(), conn)?;
Ok(revisions)
}
fn read_revision(&self, doc_id: &str, rev_id: i64) -> Result<Option<Revision>, Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
let some = RevTableSql::read_rev_table(doc_id, &rev_id, &*conn)?;
let some = RevTableSql::read_rev_table(&self.user_id, doc_id, &rev_id, &*conn)?;
Ok(some)
}
fn read_revisions(&self, doc_id: &str) -> Result<Vec<Revision>, Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
let some = RevTableSql::read_rev_tables(doc_id, &*conn)?;
let some = RevTableSql::read_rev_tables(&self.user_id, doc_id, &*conn)?;
Ok(some)
}
}
impl Persistence {
pub(crate) fn new(pool: Arc<ConnectionPool>) -> Self { Self { pool } }
pub(crate) fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
Self {
user_id: user_id.to_owned(),
pool,
}
}
}
#[cfg(feature = "flowy_unit_test")]

View File

@ -20,16 +20,18 @@ pub trait RevisionServer: Send + Sync {
pub struct RevisionManager {
doc_id: String,
user_id: String,
rev_id_counter: RevIdCounter,
cache: Arc<RevisionCache>,
ws_sender: Arc<dyn DocumentWebSocket>,
}
impl RevisionManager {
pub fn new(doc_id: &str, cache: Arc<RevisionCache>, ws_sender: Arc<dyn DocumentWebSocket>) -> Self {
pub fn new(user_id: &str, doc_id: &str, cache: Arc<RevisionCache>, ws_sender: Arc<dyn DocumentWebSocket>) -> Self {
let rev_id_counter = RevIdCounter::new(0);
Self {
doc_id: doc_id.to_string(),
user_id: user_id.to_owned(),
rev_id_counter,
cache,
ws_sender,
@ -83,6 +85,7 @@ impl RevisionManager {
delta_data.to_vec(),
&self.doc_id,
RevType::Remote,
self.user_id.clone(),
);
Ok(revision)

View File

@ -1,6 +1,6 @@
use crate::{
errors::DocError,
sql_tables::{doc::RevTable, RevChangeset, RevTableState, RevTableType},
sql_tables::{doc::RevTable, mk_revision_from_table, RevChangeset, RevTableState, RevTableType},
};
use diesel::update;
use flowy_database::{insert_or_ignore_into, prelude::*, schema::rev_table::dsl, SqliteConnection};
@ -41,7 +41,11 @@ impl RevTableSql {
Ok(())
}
pub(crate) fn read_rev_tables(doc_id: &str, conn: &SqliteConnection) -> Result<Vec<Revision>, DocError> {
pub(crate) fn read_rev_tables(
user_id: &str,
doc_id: &str,
conn: &SqliteConnection,
) -> Result<Vec<Revision>, DocError> {
let filter = dsl::rev_table
.filter(dsl::doc_id.eq(doc_id))
.order(dsl::rev_id.asc())
@ -49,12 +53,13 @@ impl RevTableSql {
let rev_tables = filter.load::<RevTable>(conn)?;
let revisions = rev_tables
.into_iter()
.map(|table| table.into())
.map(|table| mk_revision_from_table(user_id, table))
.collect::<Vec<Revision>>();
Ok(revisions)
}
pub(crate) fn read_rev_table(
user_id: &str,
doc_id: &str,
revision_id: &i64,
conn: &SqliteConnection,
@ -67,25 +72,26 @@ impl RevTableSql {
if Err(diesel::NotFound) == result {
Ok(None)
} else {
Ok(Some(result?.into()))
Ok(Some(mk_revision_from_table(user_id, result?)))
}
}
pub(crate) fn read_rev_tables_with_range(
doc_id_s: &str,
user_id: &str,
doc_id: &str,
range: RevisionRange,
conn: &SqliteConnection,
) -> Result<Vec<Revision>, DocError> {
let rev_tables = dsl::rev_table
.filter(dsl::rev_id.ge(range.start))
.filter(dsl::rev_id.le(range.end))
.filter(dsl::doc_id.eq(doc_id_s))
.filter(dsl::doc_id.eq(doc_id))
.order(dsl::rev_id.asc())
.load::<RevTable>(conn)?;
let revisions = rev_tables
.into_iter()
.map(|table| table.into())
.map(|table| mk_revision_from_table(user_id, table))
.collect::<Vec<Revision>>();
Ok(revisions)
}

View File

@ -1,5 +1,6 @@
use diesel::sql_types::Integer;
use flowy_database::schema::rev_table;
use flowy_document_infra::util::md5;
use lib_ot::revision::{RevId, RevState, RevType, Revision};
@ -63,17 +64,16 @@ impl std::convert::From<RevState> for RevTableState {
}
}
impl std::convert::From<RevTable> for Revision {
fn from(table: RevTable) -> Self {
let md5 = md5(&table.data);
Revision {
base_rev_id: table.base_rev_id,
rev_id: table.rev_id,
delta_data: table.data,
md5,
doc_id: table.doc_id,
ty: table.ty.into(),
}
pub(crate) fn mk_revision_from_table(user_id: &str, table: RevTable) -> Revision {
let md5 = md5(&table.data);
Revision {
base_rev_id: table.base_rev_id,
rev_id: table.rev_id,
delta_data: table.data,
md5,
doc_id: table.doc_id,
ty: table.ty.into(),
user_id: user_id.to_owned(),
}
}

View File

@ -1,5 +1,5 @@
use flowy_test::editor::{EditorScript::*, *};
use lib_ot::{core::DeltaBuilder, revision::RevState, rich_text::RichTextDeltaBuilder};
use lib_ot::{revision::RevState, rich_text::RichTextDeltaBuilder};
#[tokio::test]
async fn doc_rev_state_test1() {

View File

@ -9,7 +9,7 @@ use lib_ot::{
revision::{RevState, RevType, Revision, RevisionRange},
rich_text::RichTextDelta,
};
use std::{str::FromStr, sync::Arc};
use std::sync::Arc;
use tokio::time::{sleep, Duration};
pub enum EditorScript {
@ -56,10 +56,12 @@ impl EditorTest {
let _memory_cache = cache.memory_cache();
let _disk_cache = cache.dish_cache();
let doc_id = self.editor.doc_id.clone();
let user_id = self.sdk.user_session.user_id().unwrap();
match script {
EditorScript::InsertText(s, offset) => {
self.editor.insert(offset, s).await.unwrap();
sleep(Duration::from_millis(200)).await;
},
EditorScript::Delete(interval) => {
self.editor.delete(interval).await.unwrap();
@ -98,6 +100,7 @@ impl EditorTest {
delta.to_bytes().to_vec(),
&doc_id,
RevType::Remote,
user_id,
);
let data = WsDocumentDataBuilder::build_push_rev_message(&doc_id, revision);
self.send_ws_message(data).await;

View File

@ -184,6 +184,8 @@ impl UserSession {
pub fn user_id(&self) -> Result<String, UserError> { Ok(self.get_session()?.user_id) }
pub fn user_name(&self) -> Result<String, UserError> { Ok(self.get_session()?.name) }
pub fn token(&self) -> Result<String, UserError> { Ok(self.get_session()?.token) }
pub fn add_ws_handler(&self, handler: Arc<dyn WsMessageHandler>) { let _ = self.ws_manager.add_handler(handler); }

View File

@ -47,7 +47,13 @@ pub fn make_de_token_steam(ctxt: &Ctxt, ast: &ASTContainer) -> Option<TokenStrea
fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option<TokenStream> {
let member = &field.member;
let ident = get_member_ident(ctxt, member)?;
let ty_info = parse_ty(ctxt, &field.ty)?;
let ty_info = match parse_ty(ctxt, &field.ty) {
Ok(ty_info) => ty_info,
Err(e) => {
eprintln!("token_stream_for_one_of failed: {:?} with error: {}", member, e);
panic!();
}
}?;
let bracketed_ty_info = ty_info.bracket_ty_info.as_ref().as_ref();
let has_func = format_ident!("has_{}", ident.to_string());

View File

@ -109,7 +109,7 @@ impl Document {
let text = data.to_string();
let delta = self.view.insert(&self.delta, &text, interval)?;
tracing::trace!("👉 receive change: {}", delta);
tracing::debug!("👉 receive change: {}", delta);
self.compose_delta(delta.clone())?;
Ok(delta)
}

View File

@ -32,7 +32,7 @@ impl View {
for ext in &self.insert_exts {
if let Some(mut delta) = ext.apply(delta, interval.size(), text, interval.start) {
trim(&mut delta);
tracing::trace!("[{}]: applied, delta: {}", ext.ext_name(), delta);
tracing::debug!("[{}]: applied, delta: {}", ext.ext_name(), delta);
new_delta = Some(delta);
break;
}

View File

@ -29,15 +29,6 @@ impl std::default::Default for WsDataType {
fn default() -> Self { WsDataType::Acked }
}
// #[derive(ProtoBuf, Default, Debug, Clone)]
// pub struct WsDocumentUser {
// #[pb(index = 1)]
// pub user_id: String,
//
// #[pb(index = 2)]
// pub name: String,
// }
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct WsDocumentData {
#[pb(index = 1)]
@ -48,8 +39,6 @@ pub struct WsDocumentData {
#[pb(index = 3)]
pub data: Vec<u8>,
/* #[pb(index = 4)]
* pub user: WsDocumentUser, */
}
impl std::convert::From<Revision> for WsDocumentData {

View File

@ -28,7 +28,7 @@ pub struct SignInParams {
pub name: String,
}
#[derive(Debug, Default, ProtoBuf)]
#[derive(Debug, Default, ProtoBuf, Clone)]
pub struct SignInResponse {
#[pb(index = 1)]
pub user_id: String,
@ -97,7 +97,7 @@ pub struct SignUpParams {
pub password: String,
}
#[derive(ProtoBuf, Debug, Default)]
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct SignUpResponse {
#[pb(index = 1)]
pub user_id: String,

View File

@ -32,6 +32,7 @@ pub struct Revision {
pub md5: ::std::string::String,
pub doc_id: ::std::string::String,
pub ty: RevType,
pub user_id: ::std::string::String,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -170,6 +171,32 @@ impl Revision {
pub fn set_ty(&mut self, v: RevType) {
self.ty = v;
}
// string user_id = 7;
pub fn get_user_id(&self) -> &str {
&self.user_id
}
pub fn clear_user_id(&mut self) {
self.user_id.clear();
}
// Param is passed by value, moved
pub fn set_user_id(&mut self, v: ::std::string::String) {
self.user_id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_user_id(&mut self) -> &mut ::std::string::String {
&mut self.user_id
}
// Take field
pub fn take_user_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.user_id, ::std::string::String::new())
}
}
impl ::protobuf::Message for Revision {
@ -207,6 +234,9 @@ impl ::protobuf::Message for Revision {
6 => {
::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 6, &mut self.unknown_fields)?
},
7 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.user_id)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
@ -237,6 +267,9 @@ impl ::protobuf::Message for Revision {
if self.ty != RevType::Local {
my_size += ::protobuf::rt::enum_size(6, self.ty);
}
if !self.user_id.is_empty() {
my_size += ::protobuf::rt::string_size(7, &self.user_id);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
my_size
@ -261,6 +294,9 @@ impl ::protobuf::Message for Revision {
if self.ty != RevType::Local {
os.write_enum(6, ::protobuf::ProtobufEnum::value(&self.ty))?;
}
if !self.user_id.is_empty() {
os.write_string(7, &self.user_id)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
@ -329,6 +365,11 @@ impl ::protobuf::Message for Revision {
|m: &Revision| { &m.ty },
|m: &mut Revision| { &mut m.ty },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"user_id",
|m: &Revision| { &m.user_id },
|m: &mut Revision| { &mut m.user_id },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<Revision>(
"Revision",
fields,
@ -351,6 +392,7 @@ impl ::protobuf::Clear for Revision {
self.md5.clear();
self.doc_id.clear();
self.ty = RevType::Local;
self.user_id.clear();
self.unknown_fields.clear();
}
}
@ -799,52 +841,56 @@ impl ::protobuf::reflect::ProtobufValue for RevType {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0bmodel.proto\"\xa3\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\x18\
\n\x0bmodel.proto\"\xbc\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\x18\
\x01\x20\x01(\x03R\tbaseRevId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\x03R\
\x05revId\x12\x1d\n\ndelta_data\x18\x03\x20\x01(\x0cR\tdeltaData\x12\x10\
\n\x03md5\x18\x04\x20\x01(\tR\x03md5\x12\x15\n\x06doc_id\x18\x05\x20\x01\
(\tR\x05docId\x12\x18\n\x02ty\x18\x06\x20\x01(\x0e2\x08.RevTypeR\x02ty\"\
\x1d\n\x05RevId\x12\x14\n\x05value\x18\x01\x20\x01(\x03R\x05value\"N\n\r\
RevisionRange\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x14\n\
\x05start\x18\x02\x20\x01(\x03R\x05start\x12\x10\n\x03end\x18\x03\x20\
\x01(\x03R\x03end*\x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Re\
mote\x10\x01J\xea\x05\n\x06\x12\x04\0\0\x15\x01\n\x08\n\x01\x0c\x12\x03\
\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\t\x01\n\n\n\x03\x04\0\x01\x12\x03\
\x02\x08\x10\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x04\
\0\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\n\
\x15\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x18\x19\n\x0b\n\x04\x04\0\
\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\
\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\n\x10\n\x0c\n\x05\x04\0\
\x02\x01\x03\x12\x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\
\x04\x19\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\
\0\x02\x02\x01\x12\x03\x05\n\x14\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\
\x05\x17\x18\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x13\n\x0c\n\x05\
\x04\0\x02\x03\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\
\x03\x06\x0b\x0e\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x11\x12\n\x0b\
\n\x04\x04\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\0\x02\x04\x05\
\x12\x03\x07\x04\n\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x0b\x11\n\
\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07\x14\x15\n\x0b\n\x04\x04\0\x02\
\x05\x12\x03\x08\x04\x13\n\x0c\n\x05\x04\0\x02\x05\x06\x12\x03\x08\x04\
\x0b\n\x0c\n\x05\x04\0\x02\x05\x01\x12\x03\x08\x0c\x0e\n\x0c\n\x05\x04\0\
\x02\x05\x03\x12\x03\x08\x11\x12\n\n\n\x02\x04\x01\x12\x04\n\0\x0c\x01\n\
\n\n\x03\x04\x01\x01\x12\x03\n\x08\r\n\x0b\n\x04\x04\x01\x02\0\x12\x03\
\x0b\x04\x14\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x0b\x04\t\n\x0c\n\x05\
\x04\x01\x02\0\x01\x12\x03\x0b\n\x0f\n\x0c\n\x05\x04\x01\x02\0\x03\x12\
\x03\x0b\x12\x13\n\n\n\x02\x04\x02\x12\x04\r\0\x11\x01\n\n\n\x03\x04\x02\
\x01\x12\x03\r\x08\x15\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0e\x04\x16\n\
\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0e\x04\n\n\x0c\n\x05\x04\x02\x02\0\
\x01\x12\x03\x0e\x0b\x11\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0e\x14\
\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x0f\x04\x14\n\x0c\n\x05\x04\x02\
\x02\x01\x05\x12\x03\x0f\x04\t\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\
\x0f\n\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0f\x12\x13\n\x0b\n\
\x04\x04\x02\x02\x02\x12\x03\x10\x04\x12\n\x0c\n\x05\x04\x02\x02\x02\x05\
\x12\x03\x10\x04\t\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x10\n\r\n\x0c\
\n\x05\x04\x02\x02\x02\x03\x12\x03\x10\x10\x11\n\n\n\x02\x05\0\x12\x04\
\x12\0\x15\x01\n\n\n\x03\x05\0\x01\x12\x03\x12\x05\x0c\n\x0b\n\x04\x05\0\
\x02\0\x12\x03\x13\x04\x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x13\x04\t\
\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x13\x0c\r\n\x0b\n\x04\x05\0\x02\x01\
\x12\x03\x14\x04\x0f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x14\x04\n\n\
\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x14\r\x0eb\x06proto3\
(\tR\x05docId\x12\x18\n\x02ty\x18\x06\x20\x01(\x0e2\x08.RevTypeR\x02ty\
\x12\x17\n\x07user_id\x18\x07\x20\x01(\tR\x06userId\"\x1d\n\x05RevId\x12\
\x14\n\x05value\x18\x01\x20\x01(\x03R\x05value\"N\n\rRevisionRange\x12\
\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x14\n\x05start\x18\x02\
\x20\x01(\x03R\x05start\x12\x10\n\x03end\x18\x03\x20\x01(\x03R\x03end*\
\x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Remote\x10\x01J\xa1\
\x06\n\x06\x12\x04\0\0\x16\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
\x04\0\x12\x04\x02\0\n\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x10\n\x0b\
\n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x04\0\x02\0\x05\x12\
\x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\n\x15\n\x0c\n\x05\
\x04\0\x02\0\x03\x12\x03\x03\x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\x05\
\x04\0\x02\x01\x01\x12\x03\x04\n\x10\n\x0c\n\x05\x04\0\x02\x01\x03\x12\
\x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x19\n\x0c\n\
\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\
\x12\x03\x05\n\x14\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x17\x18\n\
\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x13\n\x0c\n\x05\x04\0\x02\x03\
\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06\x0b\x0e\
\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x11\x12\n\x0b\n\x04\x04\0\x02\
\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x04\n\
\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x0b\x11\n\x0c\n\x05\x04\0\x02\
\x04\x03\x12\x03\x07\x14\x15\n\x0b\n\x04\x04\0\x02\x05\x12\x03\x08\x04\
\x13\n\x0c\n\x05\x04\0\x02\x05\x06\x12\x03\x08\x04\x0b\n\x0c\n\x05\x04\0\
\x02\x05\x01\x12\x03\x08\x0c\x0e\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\
\x08\x11\x12\n\x0b\n\x04\x04\0\x02\x06\x12\x03\t\x04\x17\n\x0c\n\x05\x04\
\0\x02\x06\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\0\x02\x06\x01\x12\x03\t\
\x0b\x12\n\x0c\n\x05\x04\0\x02\x06\x03\x12\x03\t\x15\x16\n\n\n\x02\x04\
\x01\x12\x04\x0b\0\r\x01\n\n\n\x03\x04\x01\x01\x12\x03\x0b\x08\r\n\x0b\n\
\x04\x04\x01\x02\0\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x01\x02\0\x05\x12\
\x03\x0c\x04\t\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x0c\n\x0f\n\x0c\n\
\x05\x04\x01\x02\0\x03\x12\x03\x0c\x12\x13\n\n\n\x02\x04\x02\x12\x04\x0e\
\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x15\n\x0b\n\x04\x04\x02\
\x02\0\x12\x03\x0f\x04\x16\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\x04\
\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\x0b\x11\n\x0c\n\x05\x04\x02\
\x02\0\x03\x12\x03\x0f\x14\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x10\
\x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x10\x04\t\n\x0c\n\x05\
\x04\x02\x02\x01\x01\x12\x03\x10\n\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\
\x12\x03\x10\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x11\x04\x12\n\
\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x11\x04\t\n\x0c\n\x05\x04\x02\x02\
\x02\x01\x12\x03\x11\n\r\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x11\x10\
\x11\n\n\n\x02\x05\0\x12\x04\x13\0\x16\x01\n\n\n\x03\x05\0\x01\x12\x03\
\x13\x05\x0c\n\x0b\n\x04\x05\0\x02\0\x12\x03\x14\x04\x0e\n\x0c\n\x05\x05\
\0\x02\0\x01\x12\x03\x14\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x14\
\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x15\x04\x0f\n\x0c\n\x05\x05\0\
\x02\x01\x01\x12\x03\x15\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x15\
\r\x0eb\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -7,6 +7,7 @@ message Revision {
string md5 = 4;
string doc_id = 5;
RevType ty = 6;
string user_id = 7;
}
message RevId {
int64 value = 1;

View File

@ -21,6 +21,9 @@ pub struct Revision {
#[pb(index = 6)]
pub ty: RevType,
#[pb(index = 7)]
pub user_id: String,
}
impl Revision {
@ -47,7 +50,7 @@ impl std::fmt::Debug for Revision {
}
impl Revision {
pub fn new<T1, T2, D>(base_rev_id: T1, rev_id: T2, delta: D, doc_id: &str, ty: RevType) -> Revision
pub fn new<T1, T2, D>(base_rev_id: T1, rev_id: T2, delta: D, doc_id: &str, ty: RevType, user_id: String) -> Revision
where
T1: Into<i64>,
T2: Into<i64>,
@ -70,6 +73,7 @@ impl Revision {
md5,
doc_id,
ty,
user_id,
}
}
}