def execute(self, q, args=()): """ Send a query to the Salesforce API. """ self.rowcount = None if isinstance(self.query, SalesforceQuery) or self.query is None: response = self.execute_select(q, args) #print("response : %s" % response.text) elif isinstance(self.query, SalesforceRawQuery): response = self.execute_select(q, args) elif isinstance(self.query, subqueries.InsertQuery): response = self.execute_insert(self.query) elif isinstance(self.query, subqueries.UpdateQuery): response = self.execute_update(self.query) elif isinstance(self.query, subqueries.DeleteQuery): response = self.execute_delete(self.query) else: raise DatabaseError("Unsupported query: type %s: %s" % (type(self.query), self.query)) if response and isinstance(response, list): # bulk operation SOAP if all(x['success'] for x in response): self.lastrowid = [item['id'] for item in response] # the encoding is detected automatically, e.g. from headers elif (response and response.text): # parse_float set to decimal.Decimal to avoid precision errors when # converting from the json number to a float to a Decimal object # on a model's DecimalField...converts from json number directly # a Decimal object data = response.json(parse_float=decimal.Decimal) # a SELECT query if ('totalSize' in data): self.rowcount = data['totalSize'] # a successful INSERT query, return after getting PK elif ('success' in data and 'id' in data): self.lastrowid = data['id'] return elif data['hasErrors'] == False: # save id from bulk_create even if Django don't use it if data['results'] and data['results'][0]['result']: self.lastrowid = [ item['result']['id'] for item in data['results'] ] return # something we don't recognize else: raise DatabaseError(data) if q.upper().startswith('SELECT COUNT() FROM'): # COUNT() queries in SOQL are a special case, as they don't actually return rows self.results = iter([[self.rowcount]]) else: if self.query: self.query.first_chunk_len = len(data['records']) self.first_row = data['records'][0] if data['records'] else None self.results = self.query_results(data) else: self.results = iter([])
def __init__(self, message='', data=None, response=None, verbose=False): DatabaseError.__init__(self, message) self.data = data self.response = response self.verbose = verbose if verbose: log.info("Error (debug details) %s\n%s", response.text, response.__dict__)
def reauthenticate(db_alias): if connections['salesforce'].sf_session.auth.dynamic_token is None: expire_token(db_alias) oauth = authenticate(db_alias=db_alias) return oauth['access_token'] else: # It is expected that with dynamic authentication we get a token that # is valid at least for a few future seconds, because we don't get # any password or permanent permission for it from the user. raise DatabaseError("Dynamically authenticated connection can never reauthenticate.")
def reauthenticate(self): if self.dynamic is None: self.del_token() return self.get_auth()['access_token'] else: # It is expected that with dynamic authentication we get a token that # is valid at least for a few future seconds, because we don't get # any password or permanent permission for it from the user. raise DatabaseError( "Dynamically authenticated connection can never reauthenticate." )
def prep_for_deserialize(model, record, using, init_list=None): """ Convert a record from SFDC (decoded JSON) to dict(model string, pk, fields) If fixes fields of some types. If names of required fields `init_list `are specified, then only these fields are processed. """ from salesforce.backend import base # TODO the parameter 'using' is not currently important. attribs = record.pop('attributes') mod = model.__module__.split('.') if (mod[-1] == 'models'): app_label = mod[-2] elif (hasattr(model._meta, 'app_label')): app_label = getattr(model._meta, 'app_label') else: raise ImproperlyConfigured( "Can't discover the app_label for %s, you must specify it via model meta options." ) if len(record.keys()) == 1 and model._meta.db_table in record: # this is for objects with ManyToManyField and OneToOneField while len(record) == 1: record = list(record.values())[0] if record is None: return None fields = prep_for_deserialize_inner(model, record, init_list=init_list) if init_list and set(init_list).difference(fields).difference([SF_PK]): raise DatabaseError("Not found some expected fields") return dict( model='.'.join([app_label, model.__name__]), pk=record.pop('Id'), fields=fields, )
def as_sql(self, with_limits=True, with_col_aliases=False, subquery=False): """ Creates the SQL for this query. Returns the SQL string and list of parameters. If 'with_limits' is False, any limit/offset information is not included in the query. """ # After executing the query, we must get rid of any joins the query # setup created. So, take note of alias counts before the query ran. # However we do not want to get rid of stuff done in pre_sql_setup(), # as the pre_sql_setup will modify query state in a way that forbids # another run of it. if DJANGO_19_PLUS: if with_limits and self.query.low_mark == self.query.high_mark: return '', () self.subquery = subquery refcounts_before = self.query.alias_refcount.copy() soql_trans = self.query_topology() try: extra_select, order_by, group_by = self.pre_sql_setup() if with_limits and self.query.low_mark == self.query.high_mark: return '', () distinct_fields = self.get_distinct() # This must come after 'select', 'ordering', and 'distinct' -- see # docstring of get_from_clause() for details. from_, f_params = self.get_from_clause() if DJANGO_19_PLUS: where, w_params = self.compile( self.where) if self.where is not None else ("", []) having, h_params = self.compile( self.having) if self.having is not None else ("", []) else: where, w_params = self.compile(self.query.where) having, h_params = self.compile(self.query.having) params = [] result = ['SELECT'] if self.query.distinct: result.append( self.connection.ops.distinct_sql(distinct_fields)) out_cols = [] col_idx = 1 for _, (s_sql, s_params), alias in self.select + extra_select: if alias: # fixed by removing 'AS' s_sql = '%s %s' % (s_sql, self.connection.ops.quote_name(alias)) elif with_col_aliases and not isinstance( with_col_aliases, salesforce.backend.base.DatabaseWrapper): s_sql = '%s AS %s' % (s_sql, 'Col%d' % col_idx) col_idx += 1 if soql_trans and re.match(r'^\w+\.\w+$', s_sql): tab_name, col_name = s_sql.split('.') s_sql = '%s.%s' % (soql_trans[tab_name], col_name) params.extend(s_params) out_cols.append(s_sql) result.append(', '.join(out_cols)) result.append('FROM') result.extend(from_) params.extend(f_params) if where: result.append('WHERE %s' % where) params.extend(w_params) grouping = [] for g_sql, g_params in group_by: grouping.append(g_sql) params.extend(g_params) if grouping: if distinct_fields: raise NotImplementedError( "annotate() + distinct(fields) is not implemented.") if not order_by: order_by = self.connection.ops.force_no_ordering() result.append('GROUP BY %s' % ', '.join(grouping)) if having: result.append('HAVING %s' % having) params.extend(h_params) if order_by: ordering = [] for _, (o_sql, o_params, _) in order_by: ordering.append(o_sql) params.extend(o_params) result.append('ORDER BY %s' % ', '.join(ordering)) if with_limits: if self.query.high_mark is not None: result.append('LIMIT %d' % (self.query.high_mark - self.query.low_mark)) if self.query.low_mark: if self.query.high_mark is None: val = self.connection.ops.no_limit_value() if val: result.append('LIMIT %d' % val) result.append('OFFSET %d' % self.query.low_mark) if self.query.select_for_update and self.connection.features.has_select_for_update: if self.connection.get_autocommit(): raise TransactionManagementError( "select_for_update cannot be used outside of a transaction." ) # If we've been asked for a NOWAIT query but the backend does # not support it, raise a DatabaseError otherwise we could get # an unexpected deadlock. nowait = self.query.select_for_update_nowait if nowait and not self.connection.features.has_select_for_update_nowait: raise DatabaseError( 'NOWAIT is not supported on this database backend.') result.append( self.connection.ops.for_update_sql(nowait=nowait)) return ' '.join(result), tuple(params) finally: # Finally do cleanup - get rid of the joins we created above. self.query.reset_refcounts(refcounts_before)