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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion engine/src/main/java/com/arcadedb/database/EmbeddedDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import com.arcadedb.query.sql.parser.StatementCache;
import com.arcadedb.schema.DocumentType;
import com.arcadedb.schema.EmbeddedSchema;
import com.arcadedb.schema.Property;
import com.arcadedb.schema.Schema;
import com.arcadedb.schema.VertexType;
import com.arcadedb.security.SecurityDatabaseUser;
Expand Down Expand Up @@ -732,6 +733,8 @@ public void createRecordNoLock(final Record record, final String bucketName) {
if (mode == PaginatedFile.MODE.READ_ONLY)
throw new DatabaseIsReadOnlyException("Cannot create a new record");

setDefaultValues(record);

// INVOKE EVENT CALLBACKS
if (!events.onBeforeCreate(record))
return;
Expand All @@ -745,7 +748,7 @@ public void createRecordNoLock(final Record record, final String bucketName) {
final Bucket bucket;

if (bucketName == null && record instanceof Document) {
Document doc = (Document) record;
final Document doc = (Document) record;
bucket = doc.getType().getBucketIdByRecord(doc, DatabaseContext.INSTANCE.getContext(databasePath).asyncMode);
} else
bucket = schema.getBucketByName(bucketName);
Expand Down Expand Up @@ -1626,4 +1629,23 @@ protected void checkDatabaseIsOpen() {
if (DatabaseContext.INSTANCE.getContext(databasePath) == null)
DatabaseContext.INSTANCE.init(this);
}

private void setDefaultValues(Record record) {
if (record instanceof MutableDocument) {
final MutableDocument doc = (MutableDocument) record;
final DocumentType type = doc.getType();

final Set<String> propertiesWithDefaultDefined = type.getPolymorphicPropertiesWithDefaultDefined();

for (String pName : propertiesWithDefaultDefined) {
final Object pValue = doc.get(pName);
if (pValue == null) {
final Property p = type.getPolymorphicProperty(pName);
final Object defValue = p.getDefaultValue();
if (defValue != null)
doc.set(pName, defValue);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ public ResultSet executeDDL(CommandContext ctx) {
throw new CommandExecutionException("Invalid type name or type not found: " + typez);
}

Property property = typez.getProperty(propertyName.getStringValue());
if (property == null) {
throw new CommandExecutionException("Property " + property + " not found on type " + typez);
}
final Property property = typez.getProperty(propertyName.getStringValue());
if (property == null)
throw new CommandExecutionException("Property '" + property + "' not found on type " + typez);

ResultInternal result = new ResultInternal();
result.setProperty("type", typeName.getStringValue());
Expand All @@ -76,18 +75,29 @@ public ResultSet executeDDL(CommandContext ctx) {
result.setProperty("customAttribute", customPropertyName.getStringValue());
result.setProperty("oldValue", oldValue != null ? oldValue : null);
result.setProperty("newValue", finalValue != null ? finalValue : null);
} else {
throw new UnsupportedOperationException();

// String setting = settingName.getStringValue();
// Object finalValue = settingValue.execute((Identifiable) null, ctx);
//
// result.setProperty("operation", "alter property");
// result.setProperty("attribute", setting);
// result.setProperty("oldValue", oldValue != null ? oldValue.toString() : null);
// result.setProperty("newValue", finalValue != null ? finalValue.toString() : null);
}
InternalResultSet rs = new InternalResultSet();
} else if (settingName != null) {
final String setting = settingName.getStringValue().toLowerCase();
final Object finalValue = settingValue.execute((Identifiable) null, ctx);

final Object oldValue;
switch (setting) {
case "default":
oldValue = property.getDefaultValue();
property.setDefaultValue(finalValue);
break;

default:
throw new CommandExecutionException("Setting '" + setting + "' not supported");
}

result.setProperty("operation", "alter property");
result.setProperty("attribute", setting);
result.setProperty("oldValue", oldValue != null ? oldValue : null);
result.setProperty("newValue", finalValue != null ? finalValue : null);
} else
throw new CommandExecutionException("Property '" + property + "' not found on type '" + typez + "'");

final InternalResultSet rs = new InternalResultSet();
rs.add(result);
return rs;
}
Expand Down
35 changes: 24 additions & 11 deletions engine/src/main/java/com/arcadedb/schema/DocumentType.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@
public class DocumentType {
protected final EmbeddedSchema schema;
protected final String name;
protected final List<DocumentType> superTypes = new ArrayList<>();
protected final List<DocumentType> subTypes = new ArrayList<>();
protected final List<Bucket> buckets = new ArrayList<>();
protected BucketSelectionStrategy bucketSelectionStrategy = new RoundRobinBucketSelectionStrategy();
protected final Map<String, Property> properties = new HashMap<>();
protected Map<Integer, List<IndexInternal>> bucketIndexesByBucket = new HashMap<>();
protected Map<List<String>, TypeIndex> indexesByProperties = new HashMap<>();
protected final RecordEventsRegistry events = new RecordEventsRegistry();
protected final Map<String, Object> custom = new HashMap<>();
protected final List<DocumentType> superTypes = new ArrayList<>();
protected final List<DocumentType> subTypes = new ArrayList<>();
protected final List<Bucket> buckets = new ArrayList<>();
protected BucketSelectionStrategy bucketSelectionStrategy = new RoundRobinBucketSelectionStrategy();
protected final Map<String, Property> properties = new HashMap<>();
protected Map<Integer, List<IndexInternal>> bucketIndexesByBucket = new HashMap<>();
protected Map<List<String>, TypeIndex> indexesByProperties = new HashMap<>();
protected final RecordEventsRegistry events = new RecordEventsRegistry();
protected final Map<String, Object> custom = new HashMap<>();
protected Set<String> propertiesWithDefaultDefined = Collections.emptySet();

public DocumentType(final EmbeddedSchema schema, final String name) {
this.schema = schema;
Expand All @@ -62,6 +63,16 @@ public RecordEvents getEvents() {
return events;
}

public Set<String> getPolymorphicPropertiesWithDefaultDefined() {
if (superTypes.isEmpty())
return propertiesWithDefaultDefined;

final HashSet<String> set = new HashSet<>(propertiesWithDefaultDefined);
for (DocumentType superType : superTypes)
set.addAll(superType.propertiesWithDefaultDefined);
return set;
}

public DocumentType addSuperType(final String superName) {
return addSuperType(schema.getType(superName));
}
Expand Down Expand Up @@ -159,8 +170,10 @@ public Set<String> getPropertyNames() {
}

public Set<String> getPolymorphicPropertyNames() {
final Set<String> allProperties = new HashSet<>();
allProperties.addAll(getPropertyNames());
if (superTypes.isEmpty())
return getPropertyNames();

final Set<String> allProperties = new HashSet<>(getPropertyNames());
for (DocumentType p : superTypes)
allProperties.addAll(p.getPolymorphicPropertyNames());
return allProperties;
Expand Down
13 changes: 12 additions & 1 deletion engine/src/main/java/com/arcadedb/schema/EmbeddedSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,14 @@ protected synchronized void readConfiguration() {
if (schemaProperties != null) {
for (String propName : schemaProperties.keySet()) {
final JSONObject prop = schemaProperties.getJSONObject(propName);
type.createProperty(propName, (String) prop.get("type"));
final Property p = type.createProperty(propName, (String) prop.get("type"));

if (prop.has("default"))
p.setDefaultValue(prop.get("default"));

p.custom.clear();
if (prop.has("custom"))
p.custom.putAll(prop.getJSONObject("custom").toMap());
}
}
}
Expand Down Expand Up @@ -1247,6 +1254,10 @@ else if (t instanceof EdgeType)
final Property p = t.getProperty(propName);
prop.put("type", p.getType());

final Object defValue = p.getDefaultValue();
if (defValue != null)
prop.put("default", defValue);

prop.put("custom", new JSONObject(p.custom));
}

Expand Down
32 changes: 30 additions & 2 deletions engine/src/main/java/com/arcadedb/schema/Property.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class Property {
private final Type type;
private final int id;
protected final Map<String, Object> custom = new HashMap<>();
private Object defaultValue;

public Property(final DocumentType owner, final String name, final Type type) {
this.owner = owner;
Expand Down Expand Up @@ -69,6 +70,26 @@ public int getId() {
return id;
}

public Object getDefaultValue() {
return defaultValue;
}

public void setDefaultValue(final Object defaultValue) {
if (!Objects.equals(this.defaultValue, defaultValue)) {
this.defaultValue = defaultValue;

// REPLACE THE SET OF PROPERTIES WITH DEFAULT VALUES DEFINED
final Set<String> propertiesWithDefaultDefined = new HashSet<>(owner.propertiesWithDefaultDefined);
if (defaultValue == null)
propertiesWithDefaultDefined.remove(name);
else
propertiesWithDefaultDefined.add(name);
owner.propertiesWithDefaultDefined = Collections.unmodifiableSet(propertiesWithDefaultDefined);

owner.getSchema().getEmbedded().saveConfiguration();
}
}

public Set<String> getCustomKeys() {
return Collections.unmodifiableSet(custom.keySet());
}
Expand All @@ -78,9 +99,16 @@ public Object getCustomValue(final String key) {
}

public Object setCustomValue(final String key, final Object value) {
Object prev;
if (value == null)
return custom.remove(key);
return custom.put(key, value);
prev = custom.remove(key);
else
prev = custom.put(key, value);

if (!Objects.equals(prev, value))
owner.getSchema().getEmbedded().saveConfiguration();

return prev;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.arcadedb.query.sql.executor;

import com.arcadedb.TestHelper;
import com.arcadedb.graph.Vertex;
import com.arcadedb.schema.Type;
import org.json.JSONObject;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -45,8 +46,70 @@ public void sqlAlterPropertyCustom() {
Assertions.assertEquals("test", customMap.getString("description"));
Assertions.assertEquals(3, customMap.getInt("age"));

database.close();
database = factory.open();

Assertions.assertEquals("test", database.getSchema().getType("Car").getProperty("name").getCustomValue("description"));
Assertions.assertEquals(3, database.getSchema().getType("Car").getProperty("name").getCustomValue("age"));

database.command("sql", "ALTER PROPERTY Car.name CUSTOM age = null");
Assertions.assertNull(database.getSchema().getType("Car").getProperty("name").getCustomValue("age"));
Assertions.assertFalse(database.getSchema().getType("Car").getProperty("name").getCustomKeys().contains("age"));
}

@Test
public void sqlAlterPropertyDefault() {
database.command("sql", "CREATE VERTEX TYPE Car");
Assertions.assertTrue(database.getSchema().getType("Car").getSuperTypes().isEmpty());

database.command("sql", "CREATE PROPERTY Car.name STRING");
Assertions.assertTrue(database.getSchema().getType("Car").existsProperty("name"));
Assertions.assertEquals(Type.STRING, database.getSchema().getType("Car").getProperty("name").getType());

database.command("sql", "ALTER PROPERTY Car.name DEFAULT 'test'");
Assertions.assertEquals("test", database.getSchema().getType("Car").getProperty("name").getDefaultValue());

database.command("sql", "CREATE VERTEX TYPE Suv EXTENDS Car");
Assertions.assertFalse(database.getSchema().getType("Suv").getSuperTypes().isEmpty());

database.command("sql", "CREATE PROPERTY Suv.weight float");
Assertions.assertTrue(database.getSchema().getType("Suv").existsProperty("weight"));
Assertions.assertEquals(Type.FLOAT, database.getSchema().getType("Suv").getProperty("weight").getType());

database.command("sql", "ALTER PROPERTY Suv.weight DEFAULT 1");
Assertions.assertEquals(1, database.getSchema().getType("Suv").getProperty("weight").getDefaultValue());

final JSONObject cfg = database.getSchema().getEmbedded().serializeConfiguration();
String def1 = cfg.getJSONObject("types").getJSONObject("Car").getJSONObject("properties").getJSONObject("name").getString("default");
Assertions.assertEquals("test", def1);
Float def2 = cfg.getJSONObject("types").getJSONObject("Suv").getJSONObject("properties").getJSONObject("weight").getFloat("default");
Assertions.assertEquals(1, def2);

database.transaction(() -> {
database.command("sql", "CREATE VERTEX Car");
ResultSet result = database.command("sql", "SELECT FROM Car");
Assertions.assertTrue(result.hasNext());

final Vertex v = result.next().getVertex().get();
Assertions.assertEquals("test", v.get("name"));
});

database.transaction(() -> {
database.command("sql", "CREATE VERTEX Suv");
ResultSet result = database.command("sql", "SELECT FROM Suv");
Assertions.assertTrue(result.hasNext());

final Vertex v = result.next().getVertex().get();
Assertions.assertEquals("test", v.get("name"));
Assertions.assertEquals(1.0F, v.get("weight"));
});

database.close();
database = factory.open();

Assertions.assertEquals("test", database.getSchema().getType("Car").getProperty("name").getDefaultValue());

database.command("sql", "ALTER PROPERTY Car.name DEFAULT null");
Assertions.assertNull(database.getSchema().getType("Car").getProperty("name").getDefaultValue());
}
}