Search in sources :

Example 6 with QueryOptionOffset

use of siena.core.options.QueryOptionOffset in project siena by mandubian.

the class SdbMappingUtils method buildFilterOrder.

public static <T> StringBuilder buildFilterOrder(Query<T> query, StringBuilder q) {
    List<QueryFilter> filters = query.getFilters();
    Set<Field> filteredFields = new HashSet<Field>();
    boolean first = true;
    if (!filters.isEmpty()) {
        q.append(WHERE);
        for (QueryFilter filter : filters) {
            if (QueryFilterSimple.class.isAssignableFrom(filter.getClass())) {
                QueryFilterSimple qf = (QueryFilterSimple) filter;
                Field f = qf.field;
                Object value = qf.value;
                String op = qf.operator;
                // for order verification in case the order is not on a filtered field
                filteredFields.add(f);
                if (!first) {
                    q.append(AND);
                }
                first = false;
                String[] columns = ClassInfo.getColumnNames(f);
                if ("IN".equals(op)) {
                    if (!Collection.class.isAssignableFrom(value.getClass()))
                        throw new SienaException("Collection needed when using IN operator in filter() query");
                    StringBuilder s = new StringBuilder();
                    Collection<?> col = (Collection<?>) value;
                    for (Object object : col) {
                        // TO BE VERIFIED: SHOULD BE MANAGED by toString!!!
                        if (object != null) {
                            s.append("," + SimpleDB.quote(toString(f, object)));
                        } else {
                            throw new SienaException("Can't use NULL in collection for IN operator");
                        }
                    }
                    String column = null;
                    if (ClassInfo.isId(f)) {
                        column = ITEM_NAME;
                    } else {
                        column = ClassInfo.getColumnNames(f)[0];
                    }
                    q.append(column + " in(" + s.toString().substring(1) + ")");
                } else if (ClassInfo.isModel(f.getType())) {
                    // TODO could manage other ops here
                    if (!op.equals("=")) {
                        throw new SienaException("Unsupported operator for relationship: " + op);
                    }
                    ClassInfo relInfo = ClassInfo.getClassInfo(f.getType());
                    int i = 0;
                    for (Field key : relInfo.keys) {
                        if (value == null) {
                            q.append(columns[i++] + IS_NULL);
                        } else {
                            q.append(columns[i++] + op + SimpleDB.quote(objectFieldToString(value, key)));
                        }
                    }
                } else {
                    String column = null;
                    if (ClassInfo.isId(f)) {
                        column = "itemName()";
                        if (value == null && op.equals("=")) {
                            throw new SienaException("SDB filter on @Id field with 'IS NULL' is not possible");
                        }
                    } else {
                        column = ClassInfo.getColumnNames(f)[0];
                    }
                    if (value == null && op.equals("=")) {
                        q.append(column + IS_NULL);
                    } else if (value == null && op.equals("!=")) {
                        q.append(column + IS_NOT_NULL);
                    } else {
                        q.append(column + op + SimpleDB.quote(toString(f, value)));
                    }
                }
            } else if (QueryFilterSearch.class.isAssignableFrom(filter.getClass())) {
                Class<T> clazz = query.getQueriedClass();
                QueryFilterSearch qf = (QueryFilterSearch) filter;
                //	throw new SienaException("Search not possible for several fields in SDB: only one field");
                try {
                    //Field field = Util.getField(clazz, qf.fields[0]);
                    //if(field.isAnnotationPresent(Unindexed.class)){
                    //	throw new SienaException("Cannot search the @Unindexed field "+field.getName());
                    //}
                    // cuts match into words
                    String[] words = qf.match.split("\\s");
                    // if several words, then only OR operator represented by IN GAE
                    Pattern pNormal = Pattern.compile("[\\%]*(\\w+)[\\%]*");
                    if (!first) {
                        q.append(AND);
                    }
                    // forces true
                    first = true;
                    q.append(" ( ");
                    for (String f : qf.fields) {
                        Field field = Util.getField(clazz, f);
                        if (!first) {
                            q.append(OR);
                        }
                        first = false;
                        q.append(" ( ");
                        String column = null;
                        if (ClassInfo.isId(field)) {
                            column = "itemName()";
                        } else {
                            column = ClassInfo.getColumnNames(field)[0];
                        }
                        first = true;
                        for (String word : words) {
                            if (!first) {
                                q.append(OR);
                            }
                            first = false;
                            if (!pNormal.matcher(word).matches()) {
                                throw new SienaException("'" + word + "' doesn't match pattern [\\%]*(\\w+)[\\%]*");
                            }
                            if (word.contains("%")) {
                                q.append(column + LIKE + SimpleDB.quote(word));
                            } else {
                                q.append(column + EQ + SimpleDB.quote(word));
                            }
                        }
                        q.append(" ) ");
                    }
                    q.append(" ) ");
                } catch (Exception e) {
                    throw new SienaException(e);
                }
            }
        }
    }
    List<QueryOrder> orders = query.getOrders();
    if (!orders.isEmpty()) {
        QueryOrder last = orders.get(orders.size() - 1);
        Field field = last.field;
        if (ClassInfo.isId(field)) {
            if (!filteredFields.contains(field)) {
                if (filters.isEmpty()) {
                    q.append(WHERE);
                } else {
                    q.append(AND);
                }
                q.append(ITEM_NAME + IS_NOT_NULL);
            }
            q.append(ORDER_BY + ITEM_NAME);
        } else {
            String column = ClassInfo.getColumnNames(field)[0];
            if (!filteredFields.contains(field)) {
                if (filters.isEmpty()) {
                    q.append(WHERE);
                } else {
                    q.append(AND);
                }
                q.append(column + IS_NOT_NULL);
            }
            q.append(ORDER_BY + column);
        }
        if (!last.ascending)
            q.append(DESC);
    }
    QueryOptionSdbContext sdbCtx = (QueryOptionSdbContext) query.option(QueryOptionSdbContext.ID);
    QueryOptionOffset off = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
    if (sdbCtx != null && sdbCtx.realPageSize != 0) {
        if (off != null && off.isActive()) {
            // if offset is active, adds it to the page size to be sure to retrieve enough elements
            q.append(LIMIT + (sdbCtx.realPageSize + off.offset));
        } else {
            q.append(LIMIT + sdbCtx.realPageSize);
        }
    }
    return q;
}
Also used : Pattern(java.util.regex.Pattern) QueryOptionOffset(siena.core.options.QueryOptionOffset) SienaException(siena.SienaException) SienaRestrictedApiException(siena.SienaRestrictedApiException) IOException(java.io.IOException) QueryFilterSearch(siena.QueryFilterSearch) QueryOrder(siena.QueryOrder) Field(java.lang.reflect.Field) QueryFilter(siena.QueryFilter) QueryFilterSimple(siena.QueryFilterSimple) Collection(java.util.Collection) SienaException(siena.SienaException) HashSet(java.util.HashSet) ClassInfo(siena.ClassInfo)

Example 7 with QueryOptionOffset

use of siena.core.options.QueryOptionOffset in project siena by mandubian.

the class SdbPersistenceManager method doFetchList.

protected <T> void doFetchList(Query<T> query, int limit, int offset, List<T> resList, int depth) {
    if (depth >= MAX_DEPTH) {
        throw new SienaException("Reached maximum depth of recursion when retrieving more data (" + MAX_DEPTH + ")");
    }
    preFetch(query, limit, offset, !resList.isEmpty());
    QueryOptionSdbContext sdbCtx = (QueryOptionSdbContext) query.option(QueryOptionSdbContext.ID);
    QueryOptionFetchType fetchType = (QueryOptionFetchType) query.option(QueryOptionFetchType.ID);
    QueryOptionOffset off = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
    // if previousPage has detected there is no more data, simply returns an empty list
    if (sdbCtx.noMoreDataBefore || sdbCtx.noMoreDataAfter) {
        return;
    }
    // manages cursor limitations for IN and != operators with offsets
    if (!sdbCtx.isActive()) {
        StringBuffer domainBuf = new StringBuffer();
        SelectRequest req = SdbMappingUtils.buildQuery(query, prefix, domainBuf);
        req.setConsistentRead(isReadConsistent());
        checkDomain(domainBuf.toString());
        SelectResult res = sdb.select(req);
        // activates the SdbCtx now that it is really initialised
        sdbCtx.activate();
        postFetch(query, res);
        // cursor not yet created
        switch(fetchType.fetchType) {
            case KEYS_ONLY:
                if (off.isActive()) {
                    SdbMappingUtils.mapSelectResultToListKeysOnly(res, resList, query.getQueriedClass(), off.offset);
                } else {
                    SdbMappingUtils.mapSelectResultToListKeysOnly(res, resList, query.getQueriedClass());
                }
                break;
            case NORMAL:
            default:
                if (off.isActive()) {
                    SdbMappingUtils.mapSelectResultToList(res, resList, query.getQueriedClass(), off.offset);
                } else {
                    SdbMappingUtils.mapSelectResultToList(res, resList, query.getQueriedClass());
                }
                // join management
                if (!query.getJoins().isEmpty() || !ClassInfo.getClassInfo(query.getQueriedClass()).joinFields.isEmpty())
                    mapJoins(query, resList);
        }
        continueFetchNextToken(query, resList, depth);
        postMapping(query);
    } else {
        // we prepare the query each time
        StringBuffer domainBuf = new StringBuffer();
        SelectRequest req = SdbMappingUtils.buildQuery(query, prefix, domainBuf);
        req.setConsistentRead(isReadConsistent());
        checkDomain(domainBuf.toString());
        // we can't use real asynchronous function with cursors
        // so the page is extracted at once and wrapped into a SienaFuture			
        String token = sdbCtx.currentToken();
        if (token != null) {
            req.setNextToken(token);
        }
        SelectResult res = sdb.select(req);
        postFetch(query, res);
        switch(fetchType.fetchType) {
            case KEYS_ONLY:
                if (off.isActive()) {
                    SdbMappingUtils.mapSelectResultToListKeysOnly(res, resList, query.getQueriedClass(), off.offset);
                } else {
                    SdbMappingUtils.mapSelectResultToListKeysOnly(res, resList, query.getQueriedClass());
                }
                break;
            case NORMAL:
            default:
                if (off.isActive()) {
                    SdbMappingUtils.mapSelectResultToList(res, resList, query.getQueriedClass(), off.offset);
                } else {
                    SdbMappingUtils.mapSelectResultToList(res, resList, query.getQueriedClass());
                }
                // join management
                if (!query.getJoins().isEmpty() || !ClassInfo.getClassInfo(query.getQueriedClass()).joinFields.isEmpty())
                    mapJoins(query, resList);
        }
        continueFetchNextToken(query, resList, depth);
        postMapping(query);
    }
}
Also used : QueryOptionOffset(siena.core.options.QueryOptionOffset) SelectResult(com.amazonaws.services.simpledb.model.SelectResult) SienaException(siena.SienaException) QueryOptionFetchType(siena.core.options.QueryOptionFetchType) SelectRequest(com.amazonaws.services.simpledb.model.SelectRequest)

Example 8 with QueryOptionOffset

use of siena.core.options.QueryOptionOffset in project siena by mandubian.

the class SdbMappingUtils method previousPage.

public static <T> void previousPage(QueryData<T> query) {
    QueryOptionPage pag = (QueryOptionPage) query.option(QueryOptionPage.ID);
    QueryOptionState state = (QueryOptionState) query.option(QueryOptionState.ID);
    QueryOptionSdbContext sdbCtx = (QueryOptionSdbContext) query.option(QueryOptionSdbContext.ID);
    if (sdbCtx == null) {
        sdbCtx = new QueryOptionSdbContext();
        query.options().put(sdbCtx.type, sdbCtx);
    }
    // if no more data before, doesn't try to go before
    if (sdbCtx.noMoreDataBefore) {
        return;
    }
    // if no more data after, removes flag to be able to go before
    if (sdbCtx.noMoreDataAfter) {
        // here the realoffset is not at the end of current pages
        // but at the beginning of the last page
        // so need to fake that we are at the end of the last page
        sdbCtx.realOffset += pag.pageSize;
        sdbCtx.noMoreDataAfter = false;
    }
    if (pag.isPaginating()) {
        if (sdbCtx.hasToken()) {
            // if tokenIdx is 0, it means at first page after beginning 
            if (sdbCtx.tokenIdx == 0) {
                sdbCtx.previousToken();
                // follows the real offset
                sdbCtx.realOffset -= pag.pageSize;
                // uses offset
                if (sdbCtx.currentTokenOffset() <= sdbCtx.realOffset) {
                    QueryOptionOffset offset = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
                    offset.activate();
                    offset.offset = sdbCtx.realOffset - sdbCtx.currentTokenOffset();
                } else // if currentokenoffset is greater than previous page realoffset
                // go to previous page again
                {
                    previousPage(query);
                }
            } else {
                if (sdbCtx.previousToken() == null) {
                    sdbCtx.realOffset -= pag.pageSize;
                    // so now uses realOffset
                    if (sdbCtx.realOffset >= 0) {
                        QueryOptionOffset offset = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
                        offset.activate();
                        offset.offset = sdbCtx.realOffset;
                    } else {
                        // resets realOffset to 0 because it was negative
                        sdbCtx.realOffset = 0;
                        sdbCtx.noMoreDataBefore = true;
                    }
                } else {
                    // follows the real offset
                    sdbCtx.realOffset -= pag.pageSize;
                    // uses offset
                    if (sdbCtx.currentTokenOffset() <= sdbCtx.realOffset) {
                        QueryOptionOffset offset = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
                        offset.activate();
                        offset.offset = sdbCtx.realOffset - sdbCtx.currentTokenOffset();
                    } else // if currentokenoffset is greater than previous page realoffset
                    // go to previous page again
                    {
                        previousPage(query);
                    }
                }
            }
        } else {
            QueryOptionOffset offset = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
            // to simulate the nextPage as there was no token yet
            if (sdbCtx.realOffset != 0) {
                // follows the real offset
                sdbCtx.realOffset -= pag.pageSize;
                offset.activate();
                offset.offset = sdbCtx.realOffset;
            } else {
                sdbCtx.noMoreDataBefore = true;
            }
        /*if(offset.offset != 0){
					offset.offset -= pag.pageSize;
					offset.activate();

					// follows the real offset
					sdbCtx.realOffset -= pag.pageSize;
				}else {
					// if the realOffset is not null, it means we are not at the index 0 of the table
					// so now uses realOffset
					if(sdbCtx.realOffset != 0){
						offset.activate();
						offset.offset = sdbCtx.realOffset;
					}
					sdbCtx.noMoreDataBefore = true;
				}*/
        }
    } else {
        // throws exception because it's impossible to reuse nextPage when paginating has been interrupted, the cases are too many
        throw new SienaException("Can't use nextPage after pagination has been interrupted...");
    }
}
Also used : QueryOptionOffset(siena.core.options.QueryOptionOffset) QueryOptionPage(siena.core.options.QueryOptionPage) QueryOptionState(siena.core.options.QueryOptionState) SienaException(siena.SienaException)

Example 9 with QueryOptionOffset

use of siena.core.options.QueryOptionOffset in project siena by mandubian.

the class SdbPersistenceManager method continueFetchNextToken.

protected <T> void continueFetchNextToken(Query<T> query, List<T> results, int depth) {
    QueryOptionPage pag = (QueryOptionPage) query.option(QueryOptionPage.ID);
    QueryOptionSdbContext sdbCtx = (QueryOptionSdbContext) query.option(QueryOptionSdbContext.ID);
    QueryOptionState state = (QueryOptionState) query.option(QueryOptionState.ID);
    QueryOptionOffset off = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
    // desactivates offset not to use if fetching more items from next token
    if (state.isStateless()) {
        off.passivate();
    }
    if (!pag.isActive()) {
        if (state.isStateless()) {
            // retrieves next token
            if (sdbCtx.nextToken() != null) {
                doFetchList(query, Integer.MAX_VALUE, 0, results, depth + 1);
            }
        } else {
            if (sdbCtx.currentToken() != null) {
                // desactivates offset because we don't to go on using offset while going to next tokens
                boolean b = off.isActive();
                off.passivate();
                doFetchList(query, Integer.MAX_VALUE, 0, results, depth + 1);
                // reactivate it if it was activated
                if (b)
                    off.activate();
            }
        }
    }
}
Also used : QueryOptionOffset(siena.core.options.QueryOptionOffset) QueryOptionPage(siena.core.options.QueryOptionPage) QueryOptionState(siena.core.options.QueryOptionState)

Example 10 with QueryOptionOffset

use of siena.core.options.QueryOptionOffset in project siena by mandubian.

the class SdbPersistenceManager method preFetch.

protected <T> void preFetch(Query<T> query, int limit, int offset, boolean recursing) {
    QueryOptionSdbContext sdbCtx = (QueryOptionSdbContext) query.option(QueryOptionSdbContext.ID);
    QueryOptionState state = (QueryOptionState) query.option(QueryOptionState.ID);
    QueryOptionPage pag = (QueryOptionPage) query.option(QueryOptionPage.ID);
    QueryOptionOffset off = (QueryOptionOffset) query.option(QueryOptionOffset.ID);
    if (sdbCtx == null) {
        sdbCtx = new QueryOptionSdbContext();
        query.customize(sdbCtx);
    }
    if (!pag.isPaginating()) {
        if (state.isStateless()) {
            // if not empty, it means we are recursing on tokens
            sdbCtx.reset(recursing);
        }
        // no pagination but pageOption active
        if (pag.isActive()) {
            // if local limit is set, it overrides the pageOption.pageSize
            if (limit != Integer.MAX_VALUE) {
                sdbCtx.realPageSize = limit;
            // DONT DO THAT BECAUSE IT PREVENTS GOING TO NEXT TOKENS USING PAGE SIZE
            // pageOption is passivated to be sure it is not reused
            //pag.passivate();
            } else // using pageOption.pageSize
            {
                sdbCtx.realPageSize = pag.pageSize;
            // DONT DO THAT BECAUSE IT PREVENTS GOING TO NEXT TOKENS USING PAGE SIZE
            // passivates the pageOption in stateless mode not to keep anything between 2 requests
            //if(state.isStateless()){
            //	pag.passivate();
            //}						
            }
        } else {
            if (limit != Integer.MAX_VALUE) {
                sdbCtx.realPageSize = limit;
                // activates paging (but not pagination)
                pag.activate();
            } else {
                sdbCtx.realPageSize = 0;
            }
        }
    } else {
        // paginating so use the pagesize and don't passivate pageOption
        // local limit is not taken into account
        sdbCtx.realPageSize = pag.pageSize;
    }
    // if local offset has been set, uses it
    if (offset != 0) {
        off.activate();
        off.offset = offset;
    }
}
Also used : QueryOptionOffset(siena.core.options.QueryOptionOffset) QueryOptionPage(siena.core.options.QueryOptionPage) QueryOptionState(siena.core.options.QueryOptionState)

Aggregations

QueryOptionOffset (siena.core.options.QueryOptionOffset)23 QueryOptionPage (siena.core.options.QueryOptionPage)18 QueryOptionState (siena.core.options.QueryOptionState)16 SienaException (siena.SienaException)9 QueryOptionFetchType (siena.core.options.QueryOptionFetchType)6 ArrayList (java.util.ArrayList)5 Cursor (com.google.appengine.api.datastore.Cursor)4 FetchOptions (com.google.appengine.api.datastore.FetchOptions)4 PreparedQuery (com.google.appengine.api.datastore.PreparedQuery)4 QueryResultList (com.google.appengine.api.datastore.QueryResultList)4 QueryResultIterable (com.google.appengine.api.datastore.QueryResultIterable)3 PreparedStatement (java.sql.PreparedStatement)3 ResultSet (java.sql.ResultSet)3 SQLException (java.sql.SQLException)3 SienaFutureMock (siena.core.async.SienaFutureMock)2 QueryOption (siena.core.options.QueryOption)2 SelectRequest (com.amazonaws.services.simpledb.model.SelectRequest)1 SelectResult (com.amazonaws.services.simpledb.model.SelectResult)1 IOException (java.io.IOException)1 Field (java.lang.reflect.Field)1