public async virtual Task<MobileServiceTableOperation> PeekAsync(long prevSequenceId, MobileServiceTableKind tableKind, IEnumerable<string> tableNames)
        {
            MobileServiceTableQueryDescription query = CreateQuery();

            var tableKindNode = Compare(BinaryOperatorKind.Equal, "tableKind", (int)tableKind);
            var sequenceNode = Compare(BinaryOperatorKind.GreaterThan, "sequence", prevSequenceId);

            query.Filter = new BinaryOperatorNode(BinaryOperatorKind.And, tableKindNode, sequenceNode);

            if (tableNames != null && tableNames.Any())
            {
                BinaryOperatorNode nameInList = tableNames.Select(t => Compare(BinaryOperatorKind.Equal, "tableName", t))
                                                          .Aggregate((first, second) => new BinaryOperatorNode(BinaryOperatorKind.Or, first, second));
                query.Filter = new BinaryOperatorNode(BinaryOperatorKind.And, query.Filter, nameInList);
            }

            query.Ordering.Add(new OrderByNode(new MemberAccessNode(null, "sequence"), OrderByDirection.Ascending));
            query.Top = 1;

            JObject op = await this.store.FirstOrDefault(query);
            if (op == null)
            {
                return null;
            }

            return MobileServiceTableOperation.Deserialize(op);
        }
        public async Task UpdateAsync(string tableName, MobileServiceTableKind tableKind, string id, JObject item)
        {
            var operation = new UpdateOperation(tableName, tableKind, id)
            {
                Table = await this.GetTable(tableName)
            };

            await this.ExecuteOperationAsync(operation, item);
        }
 protected MobileServiceTableOperation(string tableName, MobileServiceTableKind tableKind, string itemId)
 {
     this.Id = Guid.NewGuid().ToString();
     this.State = MobileServiceTableOperationState.Pending;
     this.TableKind = tableKind;
     this.TableName = tableName;
     this.ItemId = itemId;
     this.Version = 1;
 }
示例#4
0
 protected MobileServiceTableOperation(string tableName, MobileServiceTableKind tableKind, string itemId)
 {
     this.Id        = Guid.NewGuid().ToString();
     this.State     = MobileServiceTableOperationState.Pending;
     this.TableKind = tableKind;
     this.TableName = tableName;
     this.ItemId    = itemId;
     this.Version   = 1;
 }
        public async Task DeleteAsync(string tableName, MobileServiceTableKind tableKind, string id, JObject item)
        {
            var operation = new DeleteOperation(tableName, tableKind, id)
            {
                Table = await this.GetTable(tableName),
                Item  = item // item will be deleted from store, so we need to put it in the operation queue
            };

            await this.ExecuteOperationAsync(operation, item);
        }
        public MobileServiceSyncTable(string tableName, MobileServiceTableKind Kind, MobileServiceClient client)
        {
            Debug.Assert(tableName != null);
            Debug.Assert(client != null);

            this.MobileServiceClient = client;
            this.TableName = tableName;
            this.Kind = Kind;
            this.syncContext = (MobileServiceSyncContext)client.SyncContext;
            this.SupportedOptions = MobileServiceRemoteTableOptions.All;
        }
        public async Task PurgeAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, bool force, CancellationToken cancellationToken)
        {
            await this.EnsureInitializedAsync();

            var table = await this.GetTable(tableName);

            var queryDescription = MobileServiceTableQueryDescription.Parse(tableName, query);
            var action           = new PurgeAction(table, tableKind, queryId, queryDescription, force, this, this.opQueue, this.settings, this.Store, cancellationToken);

            await this.ExecuteSyncAction(action);
        }
        public MobileServiceSyncTable(string tableName, MobileServiceTableKind Kind, MobileServiceClient client)
        {
            Debug.Assert(tableName != null);
            Debug.Assert(client != null);

            this.MobileServiceClient = client;
            this.TableName           = tableName;
            this.Kind             = Kind;
            this.syncContext      = (MobileServiceSyncContext)client.SyncContext;
            this.SupportedOptions = MobileServiceRemoteTableOptions.All;
        }
        public async Task PurgeAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, bool force, CancellationToken cancellationToken)
        {
            await this.EnsureInitializedAsync();

            var table = await this.GetTable(tableName);

            var queryDescription = MobileServiceTableQueryDescription.Parse(tableName, query);

            using (var trackedStore = StoreChangeTrackerFactory.CreateTrackedStore(this.Store, StoreOperationSource.LocalPurge, this.storeTrackingOptions, this.client.EventManager, this.settings))
            {
                var action = new PurgeAction(table, tableKind, queryId, queryDescription, force, this, this.opQueue, this.client.EventManager, this.settings, this.Store, cancellationToken);
                await this.ExecuteSyncAction(action);
            }
        }
示例#10
0
 public PurgeAction(MobileServiceTable table,
                    MobileServiceTableKind tableKind,
                    string queryId,
                    MobileServiceTableQueryDescription query,
                    bool force,
                    MobileServiceSyncContext context,
                    OperationQueue operationQueue,
                    MobileServiceSyncSettingsManager settings,
                    IMobileServiceLocalStore store,
                    CancellationToken cancellationToken)
     : base(table, tableKind, queryId, query, null, context, operationQueue, settings, store, cancellationToken)
 {
     this.force = force;
 }
 public PurgeAction(MobileServiceTable table,
                    MobileServiceTableKind tableKind,
                    string queryId,
                    MobileServiceTableQueryDescription query,
                    bool force,
                    MobileServiceSyncContext context,
                    OperationQueue operationQueue,
                    MobileServiceSyncSettingsManager settings,
                    IMobileServiceLocalStore store,
                    CancellationToken cancellationToken)
     : base(table, tableKind, queryId, query, null, context, operationQueue, settings, store, cancellationToken)
 {
     this.force = force;
 }
 public PushAction(OperationQueue operationQueue,
                   IMobileServiceLocalStore store,
                   MobileServiceTableKind tableKind,
                   IEnumerable <string> tableNames,
                   IMobileServiceSyncHandler syncHandler,
                   MobileServiceClient client,
                   MobileServiceSyncContext context,
                   CancellationToken cancellationToken)
     : base(operationQueue, store, cancellationToken)
 {
     this.tableKind   = tableKind;
     this.tableNames  = tableNames;
     this.client      = client;
     this.syncHandler = syncHandler;
     this.context     = context;
 }
 public PushAction(OperationQueue operationQueue,
                   IMobileServiceLocalStore store,
                   MobileServiceTableKind tableKind,
                   IEnumerable<string> tableNames,
                   IMobileServiceSyncHandler syncHandler,
                   MobileServiceClient client,
                   MobileServiceSyncContext context,
                   CancellationToken cancellationToken)
     : base(operationQueue, store, cancellationToken)
 {
     this.tableKind = tableKind;
     this.tableNames = tableNames;
     this.client = client;
     this.syncHandler = syncHandler;
     this.context = context;
 }
        public async Task PushAsync(CancellationToken cancellationToken, MobileServiceTableKind tableKind, params string[] tableNames)
        {
            await this.EnsureInitializedAsync();

            // use empty handler if its not a standard table push
            var handler = tableKind == MobileServiceTableKind.Table ? this.Handler : new MobileServiceSyncHandler();

            var action = new PushAction(this.opQueue,
                                        this.Store,
                                        tableKind,
                                        tableNames,
                                        handler,
                                        this.client,
                                        this,
                                        cancellationToken);

            await this.ExecuteSyncAction(action);
        }
 public TableAction(MobileServiceTable table,
                    MobileServiceTableKind tableKind,
                    string queryId,
                    MobileServiceTableQueryDescription query,
                    IEnumerable<string> relatedTables,
                    MobileServiceSyncContext context,
                    OperationQueue operationQueue,
                    MobileServiceSyncSettingsManager settings,
                    IMobileServiceLocalStore store,
                    CancellationToken cancellationToken)
     : base(operationQueue, store, cancellationToken)
 {
     this.Table = table;
     this.TableKind = tableKind;
     this.QueryId = queryId;
     this.Query = query;
     this.RelatedTables = relatedTables;
     this.Settings = settings;
     this.Context = context;
 }
 public PullAction(MobileServiceTable table,
                   MobileServiceTableKind tableKind,
                   MobileServiceSyncContext context,
                   string queryId,
                   MobileServiceTableQueryDescription query,
                   IDictionary <string, string> parameters,
                   IEnumerable <string> relatedTables,
                   OperationQueue operationQueue,
                   MobileServiceSyncSettingsManager settings,
                   IMobileServiceLocalStore store,
                   MobileServiceRemoteTableOptions options,
                   MobileServiceObjectReader reader,
                   CancellationToken cancellationToken)
     : base(table, tableKind, queryId, query, relatedTables, context, operationQueue, settings, store, cancellationToken)
 {
     this.options    = options;
     this.parameters = parameters;
     this.cursor     = new PullCursor(query);
     this.Reader     = reader ?? new MobileServiceObjectReader();
 }
 public TableAction(MobileServiceTable table,
                    MobileServiceTableKind tableKind,
                    string queryId,
                    MobileServiceTableQueryDescription query,
                    IEnumerable <string> relatedTables,
                    MobileServiceSyncContext context,
                    OperationQueue operationQueue,
                    MobileServiceSyncSettingsManager settings,
                    IMobileServiceLocalStore store,
                    CancellationToken cancellationToken)
     : base(operationQueue, store, cancellationToken)
 {
     this.Table         = table;
     this.TableKind     = tableKind;
     this.QueryId       = queryId;
     this.Query         = query;
     this.RelatedTables = relatedTables;
     this.Settings      = settings;
     this.Context       = context;
 }
 public PullAction(MobileServiceTable table,
                   MobileServiceTableKind tableKind,
                   MobileServiceSyncContext context,
                   string queryId,
                   MobileServiceTableQueryDescription query,
                   IDictionary<string, string> parameters,
                   IEnumerable<string> relatedTables,
                   OperationQueue operationQueue,
                   MobileServiceSyncSettingsManager settings,
                   IMobileServiceLocalStore store,
                   MobileServiceRemoteTableOptions options,
                   MobileServiceObjectReader reader,
                   CancellationToken cancellationToken)
     : base(table, tableKind, queryId, query, relatedTables, context, operationQueue, settings, store, cancellationToken)
 {
     this.options = options;
     this.parameters = parameters;
     this.cursor = new PullCursor(query);
     this.Reader = reader ?? new MobileServiceObjectReader();
 }
        public async Task PushAsync(CancellationToken cancellationToken, MobileServiceTableKind tableKind, params string[] tableNames)
        {
            await this.EnsureInitializedAsync();

            // use empty handler if its not a standard table push
            var handler = tableKind == MobileServiceTableKind.Table ? this.Handler : new MobileServiceSyncHandler();

            using (var trackedStore = StoreChangeTrackerFactory.CreateTrackedStore(this.Store, StoreOperationSource.ServerPush, this.storeTrackingOptions, this.client.EventManager, this.settings))
            {
                var action = new PushAction(this.opQueue,
                                            trackedStore,
                                            tableKind,
                                            tableNames,
                                            handler,
                                            this.client,
                                            this,
                                            cancellationToken);

                await this.ExecuteSyncAction(action);
            }
        }
 public InsertOperation(string tableName, MobileServiceTableKind tableKind, string itemId)
     : base(tableName, tableKind, itemId)
 {
 }
 public InsertOperation(string tableName, MobileServiceTableKind tableKind, string itemId)
     : base(tableName, tableKind, itemId)
 {
 }
        public async Task PushAsync(CancellationToken cancellationToken, MobileServiceTableKind tableKind, params string[] tableNames)
        {
            await this.EnsureInitializedAsync();

            // use empty handler if its not a standard table push
            var handler = tableKind == MobileServiceTableKind.Table ? this.Handler : new MobileServiceSyncHandler();

            using (var trackedStore = StoreChangeTrackerFactory.CreateTrackedStore(this.Store, StoreOperationSource.ServerPush, this.storeTrackingOptions, this.client.EventManager, this.settings))
            {
                var action = new PushAction(this.opQueue,
                                          trackedStore,
                                          tableKind,
                                          tableNames,
                                          handler,
                                          this.client,
                                          this,
                                          cancellationToken);
                
                await this.ExecuteSyncAction(action);
            }
        }
        public async Task PurgeAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, bool force, CancellationToken cancellationToken)
        {
            await this.EnsureInitializedAsync();

            var table = await this.GetTable(tableName);
            var queryDescription = MobileServiceTableQueryDescription.Parse(tableName, query);

            using (var trackedStore = StoreChangeTrackerFactory.CreateTrackedStore(this.Store, StoreOperationSource.LocalPurge, this.storeTrackingOptions, this.client.EventManager, this.settings))
            {
                var action = new PurgeAction(table, tableKind, queryId, queryDescription, force, this, this.opQueue, this.client.EventManager, this.settings, this.Store, cancellationToken);
                await this.ExecuteSyncAction(action);
            }
        }
        /// <summary>
        /// Pulls all items that match the given query from the associated remote table.
        /// </summary>
        /// <param name="tableName">The name of table to pull</param>
        /// <param name="tableKind">The kind of table</param>
        /// <param name="queryId">A string that uniquely identifies this query and is used to keep track of its sync state.</param>
        /// <param name="query">An OData query that determines which items to 
        /// pull from the remote table.</param>
        /// <param name="options">An instance of <see cref="MobileServiceRemoteTableOptions"/></param>
        /// <param name="parameters">A dictionary of user-defined parameters and values to include in 
        /// the request URI query string.</param>
        /// <param name="relatedTables">
        /// List of tables that may have related records that need to be push before this table is pulled down.
        /// When no table is specified, all tables are considered related.
        /// </param>
        /// <param name="reader">An instance of <see cref="MobileServiceObjectReader"/></param>
        /// <param name="cancellationToken">The <see cref="System.Threading.CancellationToken"/> token to observe
        /// </param>
        /// <param name="pullOptions">
        /// PullOptions that determine how to pull data from the remote table
        /// </param>
        /// <returns>
        /// A task that completes when pull operation has finished.
        /// </returns>
        public async Task PullAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, MobileServiceRemoteTableOptions options, IDictionary<string, string> parameters, IEnumerable<string> relatedTables, MobileServiceObjectReader reader, CancellationToken cancellationToken, PullOptions pullOptions)
        {
            await this.EnsureInitializedAsync();

            if (parameters != null)
            {
                if (parameters.Keys.Any(k => k.Equals(MobileServiceTable.IncludeDeletedParameterName, StringComparison.OrdinalIgnoreCase)))
                {
                    throw new ArgumentException("The key '{0}' is reserved and cannot be specified as a query parameter.".FormatInvariant(MobileServiceTable.IncludeDeletedParameterName));
                }
            }

            var table = await this.GetTable(tableName);
            var queryDescription = MobileServiceTableQueryDescription.Parse(this.client.MobileAppUri, tableName, query);

            // local schema should be same as remote schema otherwise push can't function
            if (queryDescription.Selection.Any() || queryDescription.Projections.Any())
            {
                throw new ArgumentException("Pull query with select clause is not supported.", "query");
            }

            bool isIncrementalSync = !String.IsNullOrEmpty(queryId);
            if (isIncrementalSync)
            {
                if (queryDescription.Ordering.Any())
                {
                    throw new ArgumentException("Incremental pull query must not have orderby clause.", "query");
                }
                if (queryDescription.Top.HasValue || queryDescription.Skip.HasValue)
                {
                    throw new ArgumentException("Incremental pull query must not have skip or top specified.", "query");
                }
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.OrderBy) && queryDescription.Ordering.Any())
            {
                throw new ArgumentException("The supported table options does not include orderby.", "query");
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.Skip) && queryDescription.Skip.HasValue)
            {
                throw new ArgumentException("The supported table options does not include skip.", "query");
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.Top) && queryDescription.Top.HasValue)
            {
                throw new ArgumentException("The supported table options does not include top.", "query");
            }

            // let us not burden the server to calculate the count when we don't need it for pull
            queryDescription.IncludeTotalCount = false;

            using (var store = StoreChangeTrackerFactory.CreateTrackedStore(this.Store, StoreOperationSource.ServerPull, this.storeTrackingOptions, this.client.EventManager, this.settings))
            {
                var action = new PullAction(table, tableKind, this, queryId, queryDescription, parameters, relatedTables,
                    this.opQueue, this.settings, store, options, pullOptions, reader, cancellationToken);
                await this.ExecuteSyncAction(action);
            }
        }
        public async Task DeleteAsync(string tableName, MobileServiceTableKind tableKind, string id, JObject item)
        {
            var operation = new DeleteOperation(tableName, tableKind, id)
            {
                Table = await this.GetTable(tableName),
                Item = item // item will be deleted from store, so we need to put it in the operation queue
            };

            await this.ExecuteOperationAsync(operation, item);
        }
        public async Task UpdateAsync(string tableName, MobileServiceTableKind tableKind, string id, JObject item)
        {
            var operation = new UpdateOperation(tableName, tableKind, id)
            {
                Table = await this.GetTable(tableName)
            };

            await this.ExecuteOperationAsync(operation, item);
        }
        public async Task PurgeAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, bool force, CancellationToken cancellationToken)
        {
            await this.EnsureInitializedAsync();

            var table = await this.GetTable(tableName);
            var queryDescription = MobileServiceTableQueryDescription.Parse(tableName, query);
            var action = new PurgeAction(table, tableKind, queryId, queryDescription, force, this, this.opQueue, this.settings, this.Store, cancellationToken);
            await this.ExecuteSyncAction(action);
        }
        /// <summary>
        /// Pulls all items that match the given query from the associated remote table.
        /// </summary>
        /// <param name="tableName">The name of table to pull</param>
        /// <param name="tableKind">The kind of table</param>
        /// <param name="queryId">A string that uniquely identifies this query and is used to keep track of its sync state.</param>
        /// <param name="query">An OData query that determines which items to
        /// pull from the remote table.</param>
        /// <param name="options">An instance of <see cref="MobileServiceRemoteTableOptions"/></param>
        /// <param name="parameters">A dictionary of user-defined parameters and values to include in
        /// the request URI query string.</param>
        /// <param name="relatedTables">
        /// List of tables that may have related records that need to be push before this table is pulled down.
        /// When no table is specified, all tables are considered related.
        /// </param>
        /// <param name="reader">An instance of <see cref="MobileServiceObjectReader"/></param>
        /// <param name="cancellationToken">The <see cref="System.Threading.CancellationToken"/> token to observe
        /// </param>
        /// <param name="pullOptions">
        /// PullOptions that determine how to pull data from the remote table
        /// </param>
        /// <returns>
        /// A task that completes when pull operation has finished.
        /// </returns>
        public async Task PullAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, MobileServiceRemoteTableOptions options, IDictionary <string, string> parameters, IEnumerable <string> relatedTables, MobileServiceObjectReader reader, CancellationToken cancellationToken, PullOptions pullOptions)
        {
            await this.EnsureInitializedAsync();

            if (parameters != null)
            {
                if (parameters.Keys.Any(k => k.Equals(MobileServiceTable.IncludeDeletedParameterName, StringComparison.OrdinalIgnoreCase)))
                {
                    throw new ArgumentException("The key '{0}' is reserved and cannot be specified as a query parameter.".FormatInvariant(MobileServiceTable.IncludeDeletedParameterName));
                }
            }

            var table = await this.GetTable(tableName);

            var queryDescription = MobileServiceTableQueryDescription.Parse(this.client.MobileAppUri, tableName, query);

            // local schema should be same as remote schema otherwise push can't function
            if (queryDescription.Selection.Any() || queryDescription.Projections.Any())
            {
                throw new ArgumentException("Pull query with select clause is not supported.", "query");
            }

            bool isIncrementalSync = !String.IsNullOrEmpty(queryId);

            if (isIncrementalSync)
            {
                if (queryDescription.Ordering.Any())
                {
                    throw new ArgumentException("Incremental pull query must not have orderby clause.", "query");
                }
                if (queryDescription.Top.HasValue || queryDescription.Skip.HasValue)
                {
                    throw new ArgumentException("Incremental pull query must not have skip or top specified.", "query");
                }
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.OrderBy) && queryDescription.Ordering.Any())
            {
                throw new ArgumentException("The supported table options does not include orderby.", "query");
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.Skip) && queryDescription.Skip.HasValue)
            {
                throw new ArgumentException("The supported table options does not include skip.", "query");
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.Top) && queryDescription.Top.HasValue)
            {
                throw new ArgumentException("The supported table options does not include top.", "query");
            }

            // let us not burden the server to calculate the count when we don't need it for pull
            queryDescription.IncludeTotalCount = false;

            using (var store = StoreChangeTrackerFactory.CreateTrackedStore(this.Store, StoreOperationSource.ServerPull, this.storeTrackingOptions, this.client.EventManager, this.settings))
            {
                var action = new PullAction(table, tableKind, this, queryId, queryDescription, parameters, relatedTables,
                                            this.opQueue, this.settings, store, options, pullOptions, reader, cancellationToken);
                await this.ExecuteSyncAction(action);
            }
        }
        public async Task PushAsync(CancellationToken cancellationToken, MobileServiceTableKind tableKind, params string[] tableNames)
        {
            await this.EnsureInitializedAsync();

            // use empty handler if its not a standard table push
            var handler = tableKind == MobileServiceTableKind.Table ? this.Handler : new MobileServiceSyncHandler();

            var action = new PushAction(this.opQueue,
                                      this.Store,
                                      tableKind,
                                      tableNames,
                                      handler,
                                      this.client,
                                      this,
                                      cancellationToken);

            await this.ExecuteSyncAction(action);
        }
 public MobileServiceSyncTable(string tableName, MobileServiceTableKind kind, MobileServiceClient client)
     : base(tableName, kind, client)
 {
     this.remoteTable   = client.GetTable <T>();
     this.queryProvider = new MobileServiceTableQueryProvider(this);
 }
        /// <summary>
        /// Pulls all items that match the given query from the associated remote table.
        /// </summary>
        /// <param name="tableName">The name of table to pull</param>
        /// <param name="tableKind">The kind of table</param>
        /// <param name="queryId">A string that uniquely identifies this query and is used to keep track of its sync state.</param>
        /// <param name="query">An OData query that determines which items to
        /// pull from the remote table.</param>
        /// <param name="options">An instance of <see cref="MobileServiceRemoteTableOptions"/></param>
        /// <param name="parameters">A dictionary of user-defined parameters and values to include in
        /// the request URI query string.</param>
        /// <param name="relatedTables">
        /// List of tables that may have related records that need to be push before this table is pulled down.
        /// When no table is specified, all tables are considered related.
        /// </param>
        /// <param name="reader">An instance of <see cref="MobileServiceObjectReader"/></param>
        /// <param name="cancellationToken">The <see cref="System.Threading.CancellationToken"/> token to observe
        /// </param>
        /// <returns>
        /// A task that completes when pull operation has finished.
        /// </returns>
        public async Task PullAsync(string tableName, MobileServiceTableKind tableKind, string queryId, string query, MobileServiceRemoteTableOptions options, IDictionary <string, string> parameters, IEnumerable <string> relatedTables, MobileServiceObjectReader reader, CancellationToken cancellationToken)
        {
            await this.EnsureInitializedAsync();

            if (parameters != null)
            {
                if (parameters.Keys.Any(k => k.Equals(MobileServiceTable.IncludeDeletedParameterName, StringComparison.OrdinalIgnoreCase)))
                {
                    throw new ArgumentException(Resources.Pull_Cannot_Use_Reserved_Key.FormatInvariant(MobileServiceTable.IncludeDeletedParameterName));
                }

                if (parameters.Keys.Any(k => k.Equals(MobileServiceTable.SystemPropertiesQueryParameterName, StringComparison.OrdinalIgnoreCase)))
                {
                    throw new ArgumentException(Resources.Pull_Cannot_Use_Reserved_Key.FormatInvariant(MobileServiceTable.SystemPropertiesQueryParameterName));
                }
            }

            var table = await this.GetTable(tableName);

            var queryDescription = MobileServiceTableQueryDescription.Parse(this.client.ApplicationUri, tableName, query);


            // local schema should be same as remote schema otherwise push can't function
            if (queryDescription.Selection.Any() || queryDescription.Projections.Any())
            {
                throw new ArgumentException(Resources.MobileServiceSyncTable_PullWithSelectNotSupported, "query");
            }

            bool isIncrementalSync = !String.IsNullOrEmpty(queryId);

            if (isIncrementalSync)
            {
                if (queryDescription.Ordering.Any())
                {
                    throw new ArgumentException(Resources.MobileServiceSyncTable_IncrementalPullWithOrderNotAllowed, "query");
                }
                if (queryDescription.Top.HasValue || queryDescription.Skip.HasValue)
                {
                    throw new ArgumentException(Resources.MobileServiceSyncTable_IncrementalPullWithSkipTopNotSupported, "query");
                }
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.OrderBy) && queryDescription.Ordering.Any())
            {
                throw new ArgumentException(Resources.MobileServiceSyncTable_OrderByNotAllowed, "query");
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.Skip) && queryDescription.Skip.HasValue)
            {
                throw new ArgumentException(Resources.MobileServiceSyncTable_SkipNotAllowed, "query");
            }

            if (!options.HasFlag(MobileServiceRemoteTableOptions.Top) && queryDescription.Top.HasValue)
            {
                throw new ArgumentException(Resources.MobileServiceSyncTable_TopNotAllowed, "query");
            }

            // let us not burden the server to calculate the count when we don't need it for pull
            queryDescription.IncludeTotalCount = false;

            var action = new PullAction(table, tableKind, this, queryId, queryDescription, parameters, relatedTables, this.opQueue, this.settings, this.Store, options, reader, cancellationToken);

            await this.ExecuteSyncAction(action);
        }
        internal MobileServiceSyncTable GetSyncTable(string tableName, MobileServiceTableKind kind)
        {
            ValidateTableName(tableName);

            return(new MobileServiceSyncTable(tableName, kind, this));
        }
        public async virtual Task <MobileServiceTableOperation> PeekAsync(long prevSequenceId, MobileServiceTableKind tableKind, IEnumerable <string> tableNames)
        {
            MobileServiceTableQueryDescription query = CreateQuery();

            var tableKindNode = Compare(BinaryOperatorKind.Equal, "tableKind", (int)tableKind);
            var sequenceNode  = Compare(BinaryOperatorKind.GreaterThan, "sequence", prevSequenceId);

            query.Filter = new BinaryOperatorNode(BinaryOperatorKind.And, tableKindNode, sequenceNode);

            if (tableNames != null && tableNames.Any())
            {
                BinaryOperatorNode nameInList = tableNames.Select(t => Compare(BinaryOperatorKind.Equal, "tableName", t))
                                                .Aggregate((first, second) => new BinaryOperatorNode(BinaryOperatorKind.Or, first, second));
                query.Filter = new BinaryOperatorNode(BinaryOperatorKind.And, query.Filter, nameInList);
            }

            query.Ordering.Add(new OrderByNode(new MemberAccessNode(null, "sequence"), OrderByDirection.Ascending));
            query.Top = 1;

            JObject op = await this.store.FirstOrDefault(query);

            if (op == null)
            {
                return(null);
            }

            return(MobileServiceTableOperation.Deserialize(op));
        }