/// <summary> /// Applies the system property attribute to the property by renaming the property to the /// system property name. /// </summary> /// <param name="property">The property.</param> /// <param name="member">The <see cref="MemberInfo"/> that corresponds to the property.</param> private static void ApplySystemPropertyAttributes(JsonProperty property, MemberInfo member) { // Check for system property attributes MobileServiceSystemProperties systemProperties = MobileServiceSystemProperties.None; foreach (object attribute in member.GetCustomAttributes(true)) { ISystemPropertyAttribute systemProperty = attribute as ISystemPropertyAttribute; if (systemProperty != null) { if (systemProperties != MobileServiceSystemProperties.None) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, "A member can only have one system property attribute. The member '{0}' on type '{1}' has system property attributes '{2}' and '{3}'.", member.Name, member.DeclaringType.FullName, systemProperty.SystemProperty, systemProperties)); } property.PropertyName = GetSystemPropertyString(systemProperty.SystemProperty); systemProperties = systemProperty.SystemProperty; } } }
/// <summary> /// Searches over the properties and their names to determine which system properties /// have been applied to the type, and then adds an entry into the system properties cache /// for the type. /// </summary> /// <param name="type">The type.</param> /// <param name="properties">The JsonProperties of the type.</param> private void AddSystemPropertyCacheEntry(Type type, IEnumerable <JsonProperty> properties) { MobileServiceSystemProperties systemProperties = MobileServiceSystemProperties.None; foreach (JsonProperty property in properties) { MobileServiceSystemProperties systemProperty = MobileServiceSystemProperties.None; if (!property.Ignored && systemPropertyNameToEnum.TryGetValue(property.PropertyName, out systemProperty)) { // Make sure there is not already a property that has been associated with // the system property. if ((systemProperties & systemProperty) == systemProperty) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, "Only one member may have the property name '{0}' (regardless of casing) on type '{1}'.", property.PropertyName, type.FullName)); } else { systemProperties |= systemProperty; } } } this.systemPropertyCache[type] = systemProperties; }
/// <summary> /// Returns the system properties as a comma seperated list for a /// given type. Returns null if the type does not support system properties. /// </summary> /// <param name="type">The type for which to get the system properties.</param> /// <returns> /// The system properties as a comma seperated list for the given type or null /// if the type does not support system properties. /// </returns> public virtual MobileServiceSystemProperties ResolveSystemProperties(Type type) { MobileServiceSystemProperties systemProperties = MobileServiceSystemProperties.None; this.systemPropertyCache.TryGetValue(type, out systemProperties); return(systemProperties); }
/// <summary> /// Searches over the properties and their names to determine which system properties /// have been applied to the type, and then adds an entry into the system properties cache /// for the type. /// </summary> /// <param name="type">The type.</param> /// <param name="properties">The JsonProperties of the type.</param> private void AddSystemPropertyCacheEntry(Type type, IEnumerable <JsonProperty> properties) { MobileServiceSystemProperties systemProperties = MobileServiceSystemProperties.None; foreach (JsonProperty property in properties) { MobileServiceSystemProperties systemProperty = MobileServiceSystemProperties.None; if (!property.Ignored && systemPropertyNameToEnum.TryGetValue(property.PropertyName, out systemProperty)) { // Make sure there is not already a property that has been associated with // the system property. if ((systemProperties & systemProperty) == systemProperty) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, Resources.MobileServiceContractResolver_SamePropertyName, property.PropertyName, type.FullName)); } else { systemProperties |= systemProperty; } } } this.systemPropertyCache[type] = systemProperties; }
/// <summary> /// Applies the system property attribute to the property by renaming the property to the /// system property name. /// </summary> /// <param name="property">The property.</param> /// <param name="member">The <see cref="MemberInfo"/> that corresponds to the property.</param> /// <param name="isIntegerIdType">Indicates if the type that the property is on, has an integer id type or not.</param> private static void ApplySystemPropertyAttributes(JsonProperty property, MemberInfo member, bool isIntegerIdType) { // Check for system property attributes MobileServiceSystemProperties systemProperties = MobileServiceSystemProperties.None; foreach (object attribute in member.GetCustomAttributes(true)) { ISystemPropertyAttribute systemProperty = attribute as ISystemPropertyAttribute; if (systemProperty != null) { if (isIntegerIdType) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, Resources.MobileServiceContractResolver_IntegerIdTypeWithSystemPropertyAttributes, member.DeclaringType.FullName, systemProperty.SystemProperty)); } if (systemProperties != MobileServiceSystemProperties.None) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, Resources.MobileServiceContractResolver_MultipleSystemPropertyAttributes, member.Name, member.DeclaringType.FullName, systemProperty.SystemProperty, systemProperties)); } property.PropertyName = GetSystemPropertyString(systemProperty.SystemProperty); systemProperties = systemProperty.SystemProperty; } } }
/// <summary> /// Given a <see cref="MobileServiceSystemProperties"/> enum value, returns the string value with the /// correct casing and system property prefix. /// </summary> /// <param name="systemProperty">The system property.</param> /// <returns>A string of the system property with the correct casing and system property prefix.</returns> private static string GetSystemPropertyString(MobileServiceSystemProperties systemProperty) { string enumAsString = systemProperty.ToString(); char firstLetterAsLower = char.ToLowerInvariant(enumAsString[0]); return(string.Format("{0}{1}{2}", MobileServiceSerializer.SystemPropertyPrefix, firstLetterAsLower, enumAsString.Substring(1))); }
/// <summary> /// Initializes a new instance of the MobileServiceTable class. /// </summary> /// <param name="tableName"> /// The name of the table. /// </param> /// <param name="client"> /// The <see cref="MobileServiceClient"/> associated with this table. /// </param> public MobileServiceTable(string tableName, MobileServiceClient client) { Debug.Assert(tableName != null); Debug.Assert(client != null); this.TableName = tableName; this.MobileServiceClient = client; this.SystemProperties = MobileServiceSystemProperties.None; }
public async Task UpsertAsync(string tableName, IEnumerable <JObject> items, bool ignoreMissingColumns) { Arguments.IsNotNull(tableName, nameof(tableName)); Arguments.IsNotNull(items, nameof(items)); if (!tableName.StartsWith(MobileServiceLocalSystemTables.Prefix)) { IDictionary <string, string> existingRecords = null; bool analyzeUpserts = this.trackingContext.TrackingOptions.HasFlag(StoreTrackingOptions.DetectInsertsAndUpdates); bool supportsVersion = false; if (analyzeUpserts) { MobileServiceSystemProperties systemProperties = await this.settings.GetSystemPropertiesAsync(tableName); supportsVersion = systemProperties.HasFlag(MobileServiceSystemProperties.Version); existingRecords = await GetItemsAsync(tableName, items.Select(i => this.objectReader.GetId(i)), supportsVersion); } await this.store.UpsertAsync(tableName, items, ignoreMissingColumns); foreach (var item in items) { string itemId = this.objectReader.GetId(item); LocalStoreOperationKind operationKind = LocalStoreOperationKind.Upsert; if (analyzeUpserts) { if (existingRecords.ContainsKey(itemId)) { operationKind = LocalStoreOperationKind.Update; // If the update isn't a result of a local operation, check if the item exposes a version property // and if we truly have a new version (an actual change) before tracking the change. // This avoids update notifications for records that haven't changed, which would usually happen as a result of a pull // operation, because of the logic used to pull changes. if (this.trackingContext.Source != StoreOperationSource.Local && supportsVersion && string.Compare(existingRecords[itemId], item[MobileServiceSystemColumns.Version].ToString()) == 0) { continue; } } else { operationKind = LocalStoreOperationKind.Insert; } } TrackStoreOperation(tableName, itemId, operationKind); } } else { await this.store.UpsertAsync(tableName, items, ignoreMissingColumns); } }
/// <summary> /// Initializes a new instance of the MobileServiceTable class. /// </summary> /// <param name="tableName"> /// The name of the table. /// </param> /// <param name="client"> /// The <see cref="MobileServiceClient"/> associated with this table. /// </param> public MobileServiceTable(string tableName, MobileServiceClient client) { Debug.Assert(tableName != null); Debug.Assert(client != null); this.TableName = tableName; this.MobileServiceClient = client; this.SystemProperties = MobileServiceSystemProperties.None; }
/// <summary> /// Checks if the given system property should be kept or removed from the returned item /// </summary> /// <param name="propertyName"> /// Name of the system property to see if it should be removed /// </param> /// <param name="propertiesToKeep"> /// The list of system properties to be kept /// </param> /// <param name="property"> /// Type of the system property to check /// </param> /// <param name="systemPropertyName"> /// Name of the actual system property to look for /// </param> private static bool IsKeptSystemProperty(string propertyName, MobileServiceSystemProperties propertiesToKeep, MobileServiceSystemProperties property, string systemPropertyName) { if ((propertiesToKeep & property) == property && String.Equals(propertyName, systemPropertyName, StringComparison.OrdinalIgnoreCase)) { return(true); } return(false); }
/// <summary> /// Adds the tables requested system properties to the parameters collection. /// </summary> /// <param name="systemProperties">The sytem properties to add.</param> /// <param name="parameters">The parameters collection.</param> /// <returns> /// The parameters collection with any requested system properties included. /// </returns> internal static IDictionary <string, string> AddSystemProperties(MobileServiceSystemProperties systemProperties, IDictionary <string, string> parameters) { // Make sure we have a case-insensitive parameters dictionary if (parameters != null) { parameters = new Dictionary <string, string>(parameters, StringComparer.OrdinalIgnoreCase); } // If there is already a user parameter for the system properties, just use it if (parameters == null || !parameters.ContainsKey(SystemPropertiesQueryParameterName)) { string systemPropertiesString = GetSystemPropertiesString(systemProperties); if (systemPropertiesString != null) { parameters = parameters ?? new Dictionary <string, string>(); parameters.Add(SystemPropertiesQueryParameterName, systemPropertiesString); } } return(parameters); }
/// <summary> /// Gets the system properties header value from the <see cref="MobileServiceSystemProperties"/>. /// </summary> /// <param name="properties">The system properties to set in the system properties header.</param> /// <returns> /// The system properties header value. Returns null if the systemProperty value is None. /// </returns> private static string GetSystemPropertiesString(MobileServiceSystemProperties properties) { if (properties == MobileServiceSystemProperties.None) { return(null); } if (properties == MobileServiceSystemProperties.All) { return("*"); } string[] systemProperties = properties.ToString().Split(','); for (int i = 0; i < systemProperties.Length; i++) { string property = systemProperties[i].Trim(); char firstLetterAsLower = char.ToLowerInvariant(property[0]); systemProperties[i] = MobileServiceSerializer.SystemPropertyPrefix + firstLetterAsLower + property.Substring(1); } string systemPropertiesString = string.Join(",", systemProperties); return(systemPropertiesString); }
/// <summary> /// Adds the tables requested system properties to the parameters collection. /// </summary> /// <param name="systemProperties">The sytem properties to add.</param> /// <param name="parameters">The parameters collection.</param> /// <returns> /// The parameters collection with any requested system properties included. /// </returns> internal static IDictionary<string, string> AddSystemProperties(MobileServiceSystemProperties systemProperties, IDictionary<string, string> parameters) { string systemPropertiesString = GetSystemPropertiesString(systemProperties); return AddSystemParameter(parameters, SystemPropertiesQueryParameterName, systemPropertiesString); }
/// <summary> /// Adds the tables requested system properties to the parameters collection. /// </summary> /// <param name="systemProperties">The sytem properties to add.</param> /// <param name="parameters">The parameters collection.</param> /// <returns> /// The parameters collection with any requested system properties included. /// </returns> internal static IDictionary <string, string> AddSystemProperties(MobileServiceSystemProperties systemProperties, IDictionary <string, string> parameters) { string systemPropertiesString = GetSystemPropertiesString(systemProperties); return(AddSystemParameter(parameters, SystemPropertiesQueryParameterName, systemPropertiesString)); }
/// <summary> /// Gets the system properties header value from the <see cref="MobileServiceSystemProperties"/>. /// </summary> /// <param name="properties">The system properties to set in the system properties header.</param> /// <returns> /// The system properties header value. Returns null if the systemProperty value is None. /// </returns> private static string GetSystemPropertiesString(MobileServiceSystemProperties properties) { if (properties == MobileServiceSystemProperties.None) { return null; } if (properties == MobileServiceSystemProperties.All) { return "*"; } string[] systemProperties = properties.ToString().Split(','); for (int i = 0; i < systemProperties.Length; i++) { string property = systemProperties[i].Trim(); char firstLetterAsLower = char.ToLowerInvariant(property[0]); systemProperties[i] = MobileServiceSerializer.SystemPropertyPrefix + firstLetterAsLower + property.Substring(1); } string systemPropertiesString = string.Join(",", systemProperties); return systemPropertiesString; }
/// <summary> /// Adds the tables requested system properties to the parameters collection. /// </summary> /// <param name="systemProperties">The sytem properties to add.</param> /// <param name="parameters">The parameters collection.</param> /// <returns> /// The parameters collection with any requested system properties included. /// </returns> internal static IDictionary<string, string> AddSystemProperties(MobileServiceSystemProperties systemProperties, IDictionary<string, string> parameters) { // Make sure we have a case-insensitive parameters dictionary if (parameters != null) { parameters = new Dictionary<string, string>(parameters, StringComparer.OrdinalIgnoreCase); } // If there is already a user parameter for the system properties, just use it if (parameters == null || !parameters.ContainsKey(SystemPropertiesQueryParameterName)) { string systemPropertiesString = GetSystemPropertiesString(systemProperties); if (systemPropertiesString != null) { parameters = parameters ?? new Dictionary<string, string>(); parameters.Add(SystemPropertiesQueryParameterName, systemPropertiesString); } } return parameters; }
/// <summary> /// Given a <see cref="MobileServiceSystemProperty"/> enum value, returns the string value with the /// correct casing and system property prefix. /// </summary> /// <param name="systemProperty">The system property.</param> /// <returns>A string of the system property with the correct casing and system property prefix.</returns> private static string GetSystemPropertyString(MobileServiceSystemProperties systemProperty) { string enumAsString = systemProperty.ToString(); char firstLetterAsLower = char.ToLowerInvariant(enumAsString[0]); return string.Format("{0}{1}{2}", MobileServiceSerializer.SystemPropertyPrefix, firstLetterAsLower, enumAsString.Substring(1)); }
public TableDefinition(IDictionary <string, ColumnDefinition> definition, MobileServiceSystemProperties systemProperties) : base(definition, StringComparer.OrdinalIgnoreCase) { this.SystemProperties = systemProperties; }
/// <summary> /// Removes all system properties from the instance /// if the instance is determined to have a string id and therefore be for table that /// supports system properties. /// </summary> /// <param name="instance">The instance to remove the system properties from.</param> /// <param name="version">Set to the value of the version system property before it is removed.</param> /// <param name="propertiesToKeep">The system properties to keep</param> /// <returns> /// The instance with the system properties removed. /// </returns> public static JObject RemoveSystemProperties(JObject instance, out string version, MobileServiceSystemProperties propertiesToKeep = MobileServiceSystemProperties.None) { version = null; var systemProperties = new String[] { MobileServiceSerializer.CreatedAtSystemPropertyString, MobileServiceSerializer.DeletedSystemPropertyString, MobileServiceSerializer.VersionSystemPropertyString, MobileServiceSerializer.UpdatedAtSystemPropertyString }.AsEnumerable <String>(); bool haveCloned = false; foreach (JProperty property in instance.Properties()) { if (systemProperties.Contains(property.Name.ToLowerInvariant())) { // We don't want to alter the original jtoken passed in by the caller // so if we find a system property to remove, we have to clone first if (!haveCloned) { instance = instance.DeepClone() as JObject; haveCloned = true; } if (String.Equals(property.Name, MobileServiceSystemColumns.Version, StringComparison.OrdinalIgnoreCase)) { version = (string)instance[property.Name]; if ((propertiesToKeep & MobileServiceSystemProperties.Version) == MobileServiceSystemProperties.Version) { continue; } } else if (propertiesToKeep == MobileServiceSystemProperties.All || IsKeptSystemProperty(property.Name, propertiesToKeep, MobileServiceSystemProperties.CreatedAt, MobileServiceSerializer.CreatedAtSystemPropertyString) || IsKeptSystemProperty(property.Name, propertiesToKeep, MobileServiceSystemProperties.UpdatedAt, MobileServiceSerializer.UpdatedAtSystemPropertyString)) { continue; } instance.Remove(property.Name); } } return(instance); }