OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 151 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 151 Rev 156
Line 21... Line 21...
21
import org.openconcerto.sql.model.SQLSelect.LockStrength;
21
import org.openconcerto.sql.model.SQLSelect.LockStrength;
22
import org.openconcerto.sql.model.SQLTable.VirtualFields;
22
import org.openconcerto.sql.model.SQLTable.VirtualFields;
23
import org.openconcerto.sql.model.graph.Link;
23
import org.openconcerto.sql.model.graph.Link;
24
import org.openconcerto.sql.model.graph.Link.Direction;
24
import org.openconcerto.sql.model.graph.Link.Direction;
25
import org.openconcerto.sql.model.graph.Path;
25
import org.openconcerto.sql.model.graph.Path;
26
import org.openconcerto.sql.utils.ReOrder;
-
 
27
import org.openconcerto.utils.DecimalUtils;
-
 
28
import org.openconcerto.utils.ListMap;
26
import org.openconcerto.utils.ListMap;
29
import org.openconcerto.utils.SetMap;
27
import org.openconcerto.utils.SetMap;
-
 
28
import org.openconcerto.utils.Tuple2.List2;
30
 
29
 
31
import java.math.BigDecimal;
-
 
32
import java.sql.ResultSet;
30
import java.sql.ResultSet;
33
import java.sql.ResultSetMetaData;
31
import java.sql.ResultSetMetaData;
34
import java.sql.SQLException;
32
import java.sql.SQLException;
35
import java.util.ArrayList;
33
import java.util.ArrayList;
36
import java.util.Arrays;
34
import java.util.Arrays;
Line 296... Line 294...
296
     */
294
     */
297
    public final void fetchValues() {
295
    public final void fetchValues() {
298
        this.fetchValues(true);
296
        this.fetchValues(true);
299
    }
297
    }
300
 
298
 
-
 
299
    /**
-
 
300
     * Fetch up-to-date values from the DB.
-
 
301
     * 
-
 
302
     * @param useCache <code>true</code> to use the {@link SQLDataSource#isCacheEnabled() cache}.
-
 
303
     * @return this.
-
 
304
     */
301
    public final SQLRow fetchValues(final boolean useCache) {
305
    public final SQLRow fetchValues(final boolean useCache) {
302
        return this.fetchValues(useCache, useCache);
306
        return this.fetchValues(useCache, useCache);
303
    }
307
    }
304
 
308
 
-
 
309
    /**
-
 
310
     * Return a new instance with up-to-date values.
-
 
311
     * 
-
 
312
     * @param useCache <code>true</code> to use the {@link SQLDataSource#isCacheEnabled() cache}.
-
 
313
     * @return a new instance.
-
 
314
     */
-
 
315
    public final SQLRow fetchNew(final boolean useCache) {
-
 
316
        return new SQLRow(this.getTable(), this.getIDNumber()).fetchValues(useCache);
-
 
317
    }
-
 
318
 
305
    @SuppressWarnings("unchecked")
319
    @SuppressWarnings("unchecked")
306
    SQLRow fetchValues(final boolean readCache, final boolean writeCache) {
320
    SQLRow fetchValues(final boolean readCache, final boolean writeCache) {
307
        final IResultSetHandler handler = new IResultSetHandler(SQLDataSource.MAP_HANDLER, readCache, writeCache) {
321
        final IResultSetHandler handler = new IResultSetHandler(SQLDataSource.MAP_HANDLER, readCache, writeCache) {
308
            @Override
322
            @Override
309
            public Set<SQLRow> getCacheModifiers() {
323
            public Set<SQLRow> getCacheModifiers() {
Line 395... Line 409...
395
        }
409
        }
396
        assert this.getValues().containsKey(field);
410
        assert this.getValues().containsKey(field);
397
        return this.getValues().get(field);
411
        return this.getValues().get(field);
398
    }
412
    }
399
 
413
 
-
 
414
    /**
-
 
415
     * Fetch from the DB this row and the next/previous one. ATTN the rows are locked
-
 
416
     * {@link LockStrength#UPDATE for update}, but if this method is not called from within a
-
 
417
     * transaction, they will immediately be obsolete.
-
 
418
     * 
-
 
419
     * @param after <code>true</code> to return the next row, <code>false</code> to return the
-
 
420
     *        previous.
-
 
421
     * @return {@link List2#get0() this row} and the next/previous one with only
-
 
422
     *         {@link SQLTable#getOrderField()} and {@link SQLTable#getArchiveField()} fetched,
-
 
423
     *         <code>null</code> if this row doesn't exist, the {@link List2#get1() next/previous
-
 
424
     *         row} is <code>null</code> if this is the last/first row of the table or has
-
 
425
     *         <code>null</code> order.
-
 
426
     * @throws IllegalStateException if this is the {@link #isUndefined() undefined} row.
-
 
427
     */
400
    public final SQLRow getRow(boolean after) {
428
    public final List2<SQLRow> fetchThisAndSequentialRow(boolean after) throws IllegalStateException {
-
 
429
        if (this.isUndefined())
-
 
430
            throw new IllegalStateException("Cannot order against the undefined");
401
        final SQLTable t = this.getTable();
431
        final SQLTable t = this.getTable();
402
        final BigDecimal destOrder = this.getOrder();
-
 
403
        final int diff = (!after) ? -1 : 1;
432
        final int diff = (!after) ? -1 : 1;
404
 
433
 
-
 
434
        // this is one statement (subquery included) and thus atomic : the inner FOR UPDATE ensures
-
 
435
        // that the ORDER doesn't change by the time the outer query is executed
-
 
436
        // SELECT * FROM "test"."BATIMENT"
-
 
437
        // WHERE "ORDRE" >= (SELECT "ORDRE" FROM "test"."BATIMENT" WHERE "ID" = 3 FOR UPDATE)
-
 
438
        // ORDER BY "ORDRE"
-
 
439
        // LIMIT 2
-
 
440
        // FOR UPDATE;
-
 
441
 
-
 
442
        final SQLSelect selOrder = new SQLSelect();
-
 
443
        // OK to order against an archived
-
 
444
        selOrder.setArchivedPolicy(SQLSelect.BOTH);
-
 
445
        selOrder.addSelect(t.getOrderField());
-
 
446
        selOrder.setWhere(this.getWhere());
-
 
447
        selOrder.setLockStrength(LockStrength.UPDATE);
-
 
448
 
405
        final SQLSelect sel = new SQLSelect();
449
        final SQLSelect sel = new SQLSelect();
406
        // undefined must not move
450
        // don't ignore undefined or the caller might want to use its order
407
        sel.setExcludeUndefined(true);
451
        sel.setExcludeUndefined(false);
408
        // unique index prend aussi en compte les archivés
452
        // unique index prend aussi en compte les archivés
409
        sel.setArchivedPolicy(SQLSelect.BOTH);
453
        sel.setArchivedPolicy(SQLSelect.BOTH);
410
        sel.addSelect(t.getKey());
454
        sel.addSelect(t.getKey());
411
        sel.addSelect(t.getOrderField());
455
        sel.addSelect(t.getOrderField());
412
        if (t.isArchivable())
456
        if (t.isArchivable())
413
            sel.addSelect(t.getArchiveField());
457
            sel.addSelect(t.getArchiveField());
414
        sel.setWhere(new Where(t.getOrderField(), diff < 0 ? "<" : ">", destOrder));
458
        final Where orderWhere = Where.createRaw(t.getOrderField().getFieldRef() + (diff < 0 ? "<=" : ">=") + "(" + selOrder + ")", t.getOrderField());
-
 
459
        // this.getWhere() needed when ORDER is null
-
 
460
        sel.setWhere(orderWhere.or(this.getWhere()));
415
        sel.addFieldOrder(t.getOrderField(), diff < 0 ? Order.desc() : Order.asc());
461
        sel.addFieldOrder(t.getOrderField(), diff < 0 ? Order.desc() : Order.asc());
416
        sel.setLimit(1);
462
        sel.setLimit(2);
-
 
463
        sel.setLockStrength(LockStrength.UPDATE);
417
 
464
 
418
        final SQLDataSource ds = t.getBase().getDataSource();
465
        final List<SQLRow> rows = SQLRowListRSH.execute(sel);
419
        @SuppressWarnings("unchecked")
466
        assert rows.size() <= 2;
420
        final Map<String, Object> otherMap = ds.execute1(sel.asString());
-
 
421
        if (otherMap != null) {
467
        if (rows.isEmpty()) {
422
            return new SQLRow(t, otherMap);
-
 
423
        } else {
-
 
424
            return null;
468
            return null;
425
        }
-
 
426
    }
-
 
427
 
-
 
428
    /**
-
 
429
     * The free order just after or before this row.
-
 
430
     * 
-
 
431
     * @param after whether to look before or after this row.
-
 
432
     * @return a free order, or <code>null</code> if there's no room left.
-
 
433
     */
-
 
434
    public final BigDecimal getOrder(boolean after) {
-
 
435
        final BigDecimal destOrder = this.getOrder();
-
 
436
        final SQLRow otherRow = this.getRow(after);
-
 
437
        final BigDecimal otherOrder;
-
 
438
        if (otherRow != null) {
-
 
439
            otherOrder = otherRow.getOrder();
-
 
440
        } else if (after) {
-
 
441
            // dernière ligne de la table
-
 
442
            otherOrder = destOrder.add(ReOrder.DISTANCE);
-
 
443
        } else {
469
        } else {
444
            // première ligne
-
 
445
            otherOrder = ReOrder.MIN_ORDER;
470
            assert rows.get(0).equals(this);
446
        }
-
 
447
 
-
 
448
        final int decDigits = this.getTable().getOrderDecimalDigits();
-
 
449
        final BigDecimal least = BigDecimal.ONE.scaleByPowerOfTen(-decDigits);
-
 
450
        final BigDecimal distance = destOrder.subtract(otherOrder).abs();
-
 
451
        if (distance.compareTo(least) <= 0)
-
 
452
            return null;
-
 
453
        else {
-
 
454
            final BigDecimal mean = destOrder.add(otherOrder).divide(BigDecimal.valueOf(2));
-
 
455
            return DecimalUtils.round(mean, decDigits);
471
            return new List2<>(rows.get(0), rows.size() == 1 ? null : rows.get(1));
456
        }
472
        }
457
    }
473
    }
458
 
474
 
459
    @Override
475
    @Override
460
    public SQLRow getForeign(String fieldName) {
476
    public SQLRow getForeign(String fieldName) {