/// <summary> /// unpack the json value and set all custom values in the row /// </summary> private void SetRowFromCustomValues(string json, TableDef tabledef, Row row) { var customs = JsonConvert.DeserializeObject <JObject>(json, Constants.CamelSerializerSettings); foreach (var coldef in tabledef.Cols.Where(c => c.IsCustom)) { var node = customs[coldef.Name]; if (node == null) { continue; } object value = Retrovert.ParseNode(node, coldef.CSType); row.SetCustom(coldef.Name, value); } }
/// <summary> /// Convert a dictionary of custom values indexed by custom column name into json format for database storage /// </summary> public string CustomValuesToJson(TableDef tabldef, Dictionary <string, object> values) { var buf = new StringBuilder(values.Count * 20); var wri0 = new StringWriter(buf); var writer = new JsonTextWriter(wri0); writer.WriteStartObject(); foreach (var coldef in tabldef.Cols.Where(c => c.IsCustom)) { if (!values.TryGetValue(coldef.Name, out object value)) { continue; } writer.WritePropertyName(coldef.Name); writer.WriteRawValue(Retrovert.FormatRawJsonValue(coldef, value)); } writer.WriteEndObject(); return(buf.ToString()); }
/// <summary> /// if persiston was new, figure out new main row's key and set Modified.Key /// </summary> private static void AssignPersistonKey(SaveItem item) { if (!item.Modified.Key.IsNew) { return; } var mainTdef = item.DatonDef.MainTableDef; var r = RecurPoint.FromDaton(item.DatonDef, item.Modified); if (r is RowRecurPoint rr) { object pk = mainTdef.RowType.GetField(mainTdef.PrimaryKeyColName).GetValue(rr.Row); var pkdef = mainTdef.Cols.Single(c => c.Name == mainTdef.PrimaryKeyColName); string pkString = Retrovert.FormatRawJsonValue(pkdef, pk); item.Modified.Key = new PersistonKey(item.Modified.Key.Name, pkString, false); return; } //if reached here, client semantics was unexpected: it should have sent a new persiston only for a daton type //that defines a single main row; in all other cases the client should have loaded then modified an existing //persiston, even if it had no rows in it. throw new Exception("Cannot save a whole-table persiston with a daton-key identifying a primary key"); }
private async Task HandleHttpMain(MainRequest req, IUser user, MainResponse resp) { //initialize if (req.Initialze != null) { resp.DataDictionary = Retrovert.DataDictionaryToWire(DataDictionary, user, LanguageMessages); } //load datons if (req.GetDatons != null) { var getResponses = new List <GetDatonResponse>(); foreach (var drequest in req.GetDatons) { var loadResult = await GetDaton(DatonKey.Parse(drequest.Key), user, forceCheckLatest : drequest.ForceLoad); var getResponse = new GetDatonResponse { Errors = loadResult.Errors }; if (loadResult.Daton != null) //null means it was not found by key, usually { bool doReturnToCaller = loadResult.Daton.Version == null || drequest.KnownVersion != loadResult.Daton.Version; //omit if client already has the current version if (doReturnToCaller) { getResponse.CondensedDaton = new CondensedDatonResponse { CondensedDatonJson = Retrovert.ToWire(DataDictionary, loadResult.Daton, false) }; } if (drequest.DoSubscribe && loadResult.Daton is Persiston) { ClientPlex.ManageSubscribe(req.SessionKey, loadResult.Daton.Key, loadResult.Daton.Version, true); } } else { getResponse.Key = drequest.Key; //only needed if daton is not returned to client } getResponses.Add(getResponse); } resp.GetDatons = getResponses.ToArray(); } //save datons if (req.SaveDatons != null) { var diffs = new List <PersistonDiff>(); foreach (var saveRequest in req.SaveDatons) { var diff = Retrovert.FromDiff(DataDictionary, saveRequest); diffs.Add(diff); } (bool success, var results) = await SaveDatons(req.SessionKey, user, diffs.ToArray()); var saveResponses = new List <SavePersistonResponse>(); foreach (var result in results) { saveResponses.Add(new SavePersistonResponse { IsDeleted = result.IsDeleted, IsSuccess = result.IsSuccess, OldKey = result.OldKey.ToString(), NewKey = result.NewKey?.ToString(), Errors = result.Errors }); } resp.SavedPersistons = saveResponses.ToArray(); resp.SavePersistonsSuccess = success; } //change datons state if (req.ManageDatons != null) { var manageResponses = new List <ManageDatonResponse>(req.ManageDatons.Length); foreach (var mrequest in req.ManageDatons) { //what does the caller wants to change? var datonKey = DatonKey.Parse(mrequest.Key); bool wantsLock = mrequest.SubscribeState == 2; bool wantsSubscribe = mrequest.SubscribeState >= 1; //handle change in subscription //(Performance note: unsubscribe should happen before unlock so that the unlock-propogation can short circuit reloading. Ultimately //if only one client is dealing with a daton and that client releases the lock and subscription, this server can forget about it //immediately.) bool isSubscribed = false; if (datonKey is PersistonKey) { ClientPlex.ManageSubscribe(req.SessionKey, datonKey, mrequest.Version, wantsSubscribe); isSubscribed = wantsSubscribe; } //handle change in lock string lockErrorCode = ""; bool hasLock = false; if (wantsLock) { if (string.IsNullOrEmpty(mrequest.Version)) { throw new Exception("Version required to lock daton"); } (hasLock, lockErrorCode) = LockManager.RequestLock(datonKey, mrequest.Version, req.SessionKey); } else { LockManager.ReleaseLock(datonKey, req.SessionKey); } manageResponses.Add(new ManageDatonResponse { ErrorCode = lockErrorCode, Key = mrequest.Key, SubscribeState = hasLock ? 2 : (isSubscribed ? 1 : 0) }); } resp.ManageDatons = manageResponses.ToArray(); } //quit - free up locks and memory if (req.DoQuit) { ClientPlex.DeleteSession(req.SessionKey); LockManager.ReleaseLocksForSession(req.SessionKey); } }
public void ExportWhereClause(SqlSelectBuilder.Where w, SqlFlavorizer sqlFlavor) { //numeric ranges if (Utils.IsSupportedNumericType(ColDef.CSType)) { try { (string lo, string hi) = SplitOnTilde(PackedValue); if (lo != null) { decimal dlo = decimal.Parse(lo); w.AddWhere($"{ColDef.Name}>={w.NextParameterName()}", dlo); } if (hi != null) { decimal dhi = decimal.Parse(hi); w.AddWhere($"{ColDef.Name}<={w.NextParameterName()}", dhi); } } catch { throw new Exception($"Misformatted numeric parameter: {PackedValue}"); } } //dates and times else if (ColDef.CSType == typeof(DateTime)) { bool isDateOnly = ColDef.WireType == Constants.TYPE_DATE; (string lo, string hi) = SplitOnTilde(PackedValue); if (lo != null) { var dlo = Retrovert.ParseRetroDateTime(lo, isDateOnly); w.AddWhere($"{ColDef.Name}>={w.NextParameterName()}", dlo); } if (hi != null) { var dhi = Retrovert.ParseRetroDateTime(hi, isDateOnly); w.AddWhere($"{ColDef.Name}<={w.NextParameterName()}", dhi); } } else if (ColDef.CSType == typeof(bool)) { bool b; if (PackedValue == "0") { b = false; } else if (PackedValue == "1") { b = true; } else { throw new Exception($"Boolean parameter must be 0 or 1: {PackedValue}"); } w.AddWhere($"{ColDef.Name}={w.NextParameterName()}", b); } else if (ColDef.CSType == typeof(string)) { w.AddWhere($"{ColDef.Name} {sqlFlavor.LikeOperator()} {w.NextParameterName()}", sqlFlavor.LikeParamValue(PackedValue)); } else { throw new Exception($"Type {ColDef.CSType.Name} not supported as a viewon parameter"); } }