Skip to content

Commit

Permalink
Include unique indexes in procedure
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Mar 21, 2016
1 parent b32e766 commit c257843
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 8 deletions.
Expand Up @@ -284,15 +284,15 @@ class StandaloneProcedureCallAcceptanceTest extends ProcedureCallAcceptanceTest
registerDummyInOutProcedure(Neo4jTypes.NTString, Neo4jTypes.NTNumber)

// Then
an [SyntaxException] shouldBe thrownBy(execute("CALL my.first.proc('ten')"))
a [SyntaxException] shouldBe thrownBy(execute("CALL my.first.proc('ten')"))
}

test("should fail if too many arguments") {
// Given
registerDummyInOutProcedure(Neo4jTypes.NTString, Neo4jTypes.NTNumber)

// Then
an [SyntaxException] shouldBe thrownBy(execute("CALL my.first.proc('ten', 10, 42)"))
a [SyntaxException] shouldBe thrownBy(execute("CALL my.first.proc('ten', 10, 42)"))
}

test("should fail if implicit argument is missing") {
Expand Down Expand Up @@ -327,6 +327,6 @@ class StandaloneProcedureCallAcceptanceTest extends ProcedureCallAcceptanceTest

// Then
result.toList should equal(
List(Map("description" -> "INDEX ON :A(prop)", "state" -> "ONLINE")))
List(Map("description" -> "INDEX ON :A(prop)", "state" -> "ONLINE", "unique" -> false)))
}
}
Expand Up @@ -20,6 +20,8 @@
package org.neo4j.kernel.builtinprocs;

import java.util.List;
import java.util.Set;
import java.util.function.Function;

import org.neo4j.collection.RawIterator;
import org.neo4j.kernel.api.Statement;
Expand All @@ -35,6 +37,7 @@

import static org.neo4j.helpers.collection.Iterators.asList;
import static org.neo4j.helpers.collection.Iterators.asRawIterator;
import static org.neo4j.helpers.collection.Iterators.asSet;
import static org.neo4j.helpers.collection.Iterators.map;
import static org.neo4j.kernel.api.proc.CallableProcedure.Context.KERNEL_TRANSACTION;
import static org.neo4j.kernel.api.proc.ProcedureSignature.procedureSignature;
Expand All @@ -46,6 +49,7 @@ protected ListIndexesProcedure(ProcedureName procedureName)
super( procedureSignature( procedureName )
.out( "description", Neo4jTypes.NTString )
.out( "state", Neo4jTypes.NTString )
.out( "unique", Neo4jTypes.NTBoolean )
.build() );
}

Expand All @@ -58,13 +62,22 @@ public RawIterator<Object[],ProcedureException> apply( Context ctx, Object[] inp

List<IndexDescriptor> indexes =
asList( statement.readOperations().indexesGetAll() );

Set<IndexDescriptor> uniqueIndexes = asSet( statement.readOperations().uniqueIndexesGetAll() );
indexes.addAll( uniqueIndexes );
indexes.sort( (a,b) -> a.userDescription(tokens).compareTo( b.userDescription(tokens) ) );

return format( indexes, statement, tokens, uniqueIndexes::contains );
}

private RawIterator<Object[],ProcedureException> format(List<IndexDescriptor> indexes,
Statement statement, TokenNameLookup tokens, Function<IndexDescriptor, Boolean> unqiue)
{
return map( ( index ) -> {
try
{
return new Object[]{"INDEX ON " + index.userDescription( tokens ),
statement.readOperations().indexGetState( index ).toString()};
statement.readOperations().indexGetState( index ).toString(), unqiue.apply( index )};
}
catch ( IndexNotFoundKernelException e )
{
Expand Down
Expand Up @@ -61,6 +61,7 @@
public class BuiltInProceduresTest
{
private final List<IndexDescriptor> indexes = new LinkedList<>();
private final List<IndexDescriptor> uniqueIndexes = new LinkedList<>();
private final List<PropertyConstraint> constraints = new LinkedList<>();
private final Map<Integer, String> labels = new HashMap<>();
private final Map<Integer, String> propKeys = new HashMap<>();
Expand All @@ -80,8 +81,21 @@ public void shouldListAllIndexes() throws Throwable
givenIndex( "User", "name" );

// When/Then
assertThat( call("db.indexes"),
contains( record( "INDEX ON :User(name)", "ONLINE" ) ) );

List<Object[]> call = call( "db.indexes" );
assertThat( call,
contains( record( "INDEX ON :User(name)", "ONLINE", false ) ) );
}

@Test
public void shouldListAllUniqueIndexes() throws Throwable
{
// Given
givenUniqueConstraint( "User", "name" );

// When/Then
assertThat( call( "db.indexes" ),
contains( record( "INDEX ON :User(name)", "ONLINE", true ) ) );
}

@Test
Expand Down Expand Up @@ -143,7 +157,7 @@ public void shouldListCorrectBuiltinProcedures() throws Throwable
// When/Then
assertThat( call( "sys.procedures" ), contains(
record( "db.constraints", "db.constraints() :: (description :: STRING?)" ),
record( "db.indexes", "db.indexes() :: (description :: STRING?, state :: STRING?)" ),
record( "db.indexes", "db.indexes() :: (description :: STRING?, state :: STRING?, unique :: BOOLEAN?)" ),
record( "db.labels", "db.labels() :: (label :: STRING?)" ),
record( "db.propertyKeys", "db.propertyKeys() :: (propertyKey :: STRING?)" ),
record( "db.relationshipTypes", "db.relationshipTypes() :: (relationshipType :: STRING?)" ),
Expand Down Expand Up @@ -175,11 +189,20 @@ private void givenIndex( String label, String propKey )
indexes.add( new IndexDescriptor( labelId, propId ) );
}

private void givenUniqueIndex( String label, String propKey )
{
int labelId = token( label, labels );
int propId = token( propKey, propKeys );

uniqueIndexes.add( new IndexDescriptor( labelId, propId ) );
}

private void givenUniqueConstraint( String label, String propKey )
{
int labelId = token( label, labels );
int propId = token( propKey, propKeys );

uniqueIndexes.add( new IndexDescriptor( labelId, propId ) );
constraints.add( new UniquenessConstraint( labelId, propId ) );
}

Expand Down Expand Up @@ -239,6 +262,7 @@ public void setup() throws Exception
when(read.labelsGetAllTokens()).thenAnswer( asTokens(labels) );
when(read.relationshipTypesGetAllTokens()).thenAnswer( asTokens(relTypes) );
when(read.indexesGetAll()).thenAnswer( (i) -> indexes.iterator() );
when(read.uniqueIndexesGetAll()).thenAnswer( (i) -> uniqueIndexes.iterator() );
when(read.constraintsGetAll()).thenAnswer( (i) -> constraints.iterator() );
when(read.proceduresGetAll() ).thenReturn( procs.getAll() );

Expand Down
Expand Up @@ -24,12 +24,15 @@
import org.junit.rules.ExpectedException;

import org.neo4j.collection.RawIterator;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.security.AuthorizationViolationException;
import org.neo4j.kernel.api.DataWriteOperations;
import org.neo4j.kernel.api.SchemaWriteOperations;
import org.neo4j.kernel.api.exceptions.ProcedureException;
import org.neo4j.kernel.api.security.AccessMode;
import org.neo4j.server.security.auth.AuthSubject;

import static java.util.concurrent.TimeUnit.SECONDS;
import static junit.framework.TestCase.fail;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
Expand Down Expand Up @@ -153,7 +156,7 @@ public void listProcedures() throws Throwable
// Then
assertThat( asList( stream ), containsInAnyOrder(
equalTo( new Object[]{"db.constraints", "db.constraints() :: (description :: STRING?)"} ),
equalTo( new Object[]{"db.indexes", "db.indexes() :: (description :: STRING?, state :: STRING?)"} ),
equalTo( new Object[]{"db.indexes", "db.indexes() :: (description :: STRING?, state :: STRING?, unique :: BOOLEAN?)"} ),
equalTo( new Object[]{"db.propertyKeys", "db.propertyKeys() :: (propertyKey :: STRING?)"}),
equalTo( new Object[]{"db.labels", "db.labels() :: (label :: STRING?)"} ),
equalTo( new Object[]{"sys.procedures", "sys.procedures() :: (name :: STRING?, signature :: STRING?)"} ),
Expand Down Expand Up @@ -220,4 +223,49 @@ public void shouldFailWhenChangePasswordWithStaticAccessModeInDbmsMode() throws
assertThat( e.getClass(), equalTo( AuthorizationViolationException.class ) );
}
}

@Test
public void listAllIndexes() throws Throwable
{
// Given
SchemaWriteOperations ops = schemaWriteOperationsInNewTransaction();
int labelId1 = ops.labelGetOrCreateForName( "Person" );
int labelId2 = ops.labelGetOrCreateForName( "Age" );
int propertyKeyId = ops.propertyKeyGetOrCreateForName( "foo" );
ops.indexCreate( labelId1, propertyKeyId );
ops.uniquePropertyConstraintCreate( labelId2, propertyKeyId );
commit();

//let indexes come online
try ( Transaction tx = db.beginTx() )
{
db.schema().awaitIndexOnline( db.schema().getIndexes().iterator().next(), 20, SECONDS );
tx.success();
}

// When
RawIterator<Object[],ProcedureException> stream =
readOperationsInNewTransaction().procedureCallRead( procedureName( "db", "indexes" ), new Object[0] );

// Then
assertThat( stream.next(), equalTo( new Object[]{"INDEX ON :Age(foo)", "ONLINE", true} ) );
assertThat( stream.next(), equalTo( new Object[]{"INDEX ON :Person(foo)", "ONLINE", false} ) );
}

@Test
public void shouldFalilistAllIndexesnDbmsMode() throws Throwable
{
try
{
// When
RawIterator<Object[],ProcedureException> stream = dbmsOperations().procedureCallDbms( procedureName( "db", "indexes" ), new Object[0],
AccessMode.Static.NONE );
fail( "Should have failed." );
}
catch (Exception e)
{
// Then
assertThat( e.getClass(), equalTo( ProcedureException.class ) );
}
}
}

0 comments on commit c257843

Please sign in to comment.