Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,12 @@ rdf4j: root project
* Don’t commit or push unless explicitly asked.
* Don’t add new dependencies without explicit approval.

### Version Control Conventions

* Branch names must always start with the GitHub issue identifier in the form `GH-XXXX`, where `XXXX` is the numeric issue number.
* Every commit message must be prefixed with the corresponding `GH-XXXX` label.
* Exception: if no GitHub issue number is available for the task, clearly note this in your handoff and align with the requester on an appropriate branch/commit prefix before proceeding.

It is illegal to `-am` when running tests!
It is illegal to `-q` when running tests!
You must follow these rules and instructions exactly as stated.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
Expand Down Expand Up @@ -704,15 +707,24 @@ private static int key(Predicate<ChronoField> include, ChronoField... fields) {

this.value = value;

datatype = DATATYPES.get(key(value));
TemporalAccessor lexicalValue = value;

if (datatype == null) {
CoreDatatype.XSD detectedDatatype = DATATYPES.get(key(lexicalValue));

if (detectedDatatype == null && value.isSupported(ChronoField.INSTANT_SECONDS)) {
Instant instant = Instant.from(value);
lexicalValue = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
detectedDatatype = DATATYPES.get(key(lexicalValue));
}

if (detectedDatatype == null) {
throw new IllegalArgumentException(String.format(
"value <%s> cannot be represented by an XML Schema date/time datatype", value
));
}

this.label = FORMATTERS.get(datatype).format(value);
datatype = detectedDatatype;
this.label = FORMATTERS.get(datatype).format(lexicalValue);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
package org.eclipse.rdf4j.model.util;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.time.Instant;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.IllformedLocaleException;
Expand Down Expand Up @@ -107,6 +109,17 @@ public void testNormaliseBCP47Tag() {
.isThrownBy(() -> Literals.normalizeLanguageTag("ru-ua-latn"));
}

@Test
public void valuesLiteralSupportsInstant() {
Instant instant = Instant.parse("2022-08-01T21:14:38.470534100Z");

Literal literal = Values.literal(instant);

assertThat(Instant.parse(literal.getLabel())).isEqualTo(instant);
assertThat(literal.getDatatype()).isEqualTo(XSD.DATETIME);
assertThat(literal.temporalAccessorValue()).isEqualTo(instant);
}

/**
* Test method for
* {@link org.eclipse.rdf4j.model.util.Literals#getLabel(org.eclipse.rdf4j.model.Literal, java.lang.String)} .
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ public LmdbStore(LmdbStoreConfig config) {
IsolationLevels.SNAPSHOT, IsolationLevels.SERIALIZABLE);
setDefaultIsolationLevel(IsolationLevels.SNAPSHOT_READ);
config.getDefaultQueryEvaluationMode().ifPresent(this::setDefaultQueryEvaluationMode);
if (config.getIterationCacheSyncThreshold() > 0) {
setIterationCacheSyncThreshold(config.getIterationCacheSyncThreshold());
}
EvaluationStrategyFactory evalStrategyFactory = config.getEvaluationStrategyFactory();
if (evalStrategyFactory != null) {
setEvaluationStrategyFactory(evalStrategyFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.eclipse.rdf4j.model.impl.LinkedHashModel;
import org.eclipse.rdf4j.model.util.ModelBuilder;
import org.eclipse.rdf4j.model.util.Values;
import org.eclipse.rdf4j.sail.lmdb.LmdbStore;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

Expand Down Expand Up @@ -65,6 +67,17 @@ void testThatLmdbStoreConfigParseAndExportValueCacheSize(final int valueCacheSiz

// TODO: Add more tests for other properties

@Test
void setIterationCacheSyncThresholdShouldApplyToCreatedStore() {
final long threshold = 42;
final LmdbStoreConfig config = new LmdbStoreConfig();
config.setIterationCacheSyncThreshold(threshold);

final LmdbStore store = new LmdbStore(config);

assertThat(store.getIterationCacheSyncThreshold()).isEqualTo(threshold);
}

/**
* Generic method to test parsing and exporting of config properties.
*
Expand Down
4 changes: 4 additions & 0 deletions site/content/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ This is useful if you are already using Elasticsearch for other things in your p
A good usecase is if you need reference data or an ontology for your application. The built-in read cache makes it a good choice for data that updates infrequently,
though for most usecases the NativeStore will be considerably faster.

{{< alert title="Licensing note" color="warning" >}}
Elasticsearch itself is distributed under the Elastic License (with SSPL as an alternative). If you intend to use the optional Elasticsearch-backed features in RDF4J, please make sure to evaluate whether the licensing terms of Elasticsearch align with the needs of your project before adopting it.
{{< /alert >}}

On top of these core databases, RDF4J offers a number of functional extensions. These extensions add functionality such as improved full-text search, RDFS inferencing, rule-based reasoning and validation using SHACL/SPIN, and geospatial querying support. For more information see the [RDF4J documentation](/documentation).

### Third party database solutions
Expand Down
4 changes: 2 additions & 2 deletions site/content/documentation/programming/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ The ElasticsearchStore stores RDF data in Elasticsearch. Not to be confused with
The ElasticsearchStore is experimental and future releases may be incompatible with the current version. Write-ahead-logging is not supported.
This means that a write operation can appear to have partially succeeded if the ElasticsearchStore looses its connection to Elasticsearch during a commit.

Note that, while RDF4J is licensed under the EDL, several ElasticSearch dependencies are licensed under the Elastic License or the SSPL,
which may have implications for some projects.
Note that, while RDF4J is licensed under the EDL, Elasticsearch itself is distributed under the Elastic License (with SSPL as an alternative).
The Elasticsearch-backed functionality in RDF4J is optional, and adopters should carefully evaluate the Elasticsearch licensing terms to ensure they meet the needs of their projects before enabling it.
Please consult the ElasticSearch website and [license FAQ](https://www.elastic.co/licensing/elastic-license/faq) for more information.

Transaction isolation is not as strong as for the other stores. The highest supported level is READ_COMMITTED, and even this
Expand Down
19 changes: 19 additions & 0 deletions site/layouts/shortcodes/alert.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- $type := lower (default "info" (.Get "type")) -}}
{{- $title := .Get "title" -}}
{{- $icons := dict "info" "fa-info-circle" "warning" "fa-exclamation-triangle" "danger" "fa-exclamation-circle" "success" "fa-check-circle" -}}
{{- $backgrounds := dict "info" "#e0f4ff" "warning" "#fff4e0" "danger" "#ffe3e3" "success" "#e7f5e7" -}}
{{- $borders := dict "info" "#228be6" "warning" "#f08c00" "danger" "#c92a2a" "success" "#2f9e44" -}}
{{- $icon := index $icons $type | default (index $icons "info") -}}
{{- $background := index $backgrounds $type | default (index $backgrounds "info") -}}
{{- $border := index $borders $type | default (index $borders "info") -}}
<div class="alert-box alert-box-{{$type}}" role="alert" style="border-left:4px solid {{$border}}; background-color: {{$background}}; padding:1rem; margin:1rem 0; border-radius:0.5rem;">
<div style="display:flex; align-items:flex-start; gap:0.75rem;">
<i class="fa {{$icon}}" aria-hidden="true" style="font-size:1.75rem; line-height:1;"></i>
<div class="alert-box-content">
{{- if $title -}}
<p style="font-weight:600; margin:0 0 0.25rem 0;">{{$title}}</p>
{{- end -}}
<div>{{ .Inner | markdownify }}</div>
</div>
</div>
</div>
Loading