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
116 changes: 110 additions & 6 deletions test/mocha_integration_cassandra.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,23 @@ describe("Cassandra Local", function () {
});
});

it("17. Delete the associations", function () {
it("17. Read one instant and search on associated incident primary key", function () {
let res = itHelpers.request_graph_ql_post(
`{
readOneInstant(instant_id: "instant_1") {
instant_id
incident(search: {field: incident_id value:"incident_7" operator:eq}) {
incident_id
}
}
}`
);
let resBody = JSON.parse(res.body.toString("utf8"));
expect(res.statusCode).to.equal(200);
expect(resBody).to.deep.equal({"data":{"readOneInstant":{"instant_id":"instant_1","incident":{"incident_id":"incident_7"}}}})
});

it("18. Delete the associations", function () {
let res = itHelpers.request_graph_ql_post(
`{instantsConnection(pagination:{first:20}, search:{field: incident_assoc_id, operator: eq, value:"incident_7"}) {edges {node{ instant_id}}}}`
);
Expand All @@ -694,7 +710,7 @@ describe("Cassandra Local", function () {
}
});

it("18. Get the table template", function () {
it("19. Get the table template", function () {
let res = itHelpers.request_graph_ql_post(`{csvTableTemplateIncident}`);
let resBody = JSON.parse(res.body.toString("utf8"));
expect(res.statusCode).to.equal(200);
Expand All @@ -708,7 +724,7 @@ describe("Cassandra Local", function () {
});
});

it("19. Associate cassandra to sql model", function () {
it("20. Associate cassandra to sql model", function () {
// create sql-capital
let res = itHelpers.request_graph_ql_post(
`mutation { addCapital(capital_id: "cass_assoc_capital_1", name: "London") {capital_id}}`
Expand Down Expand Up @@ -1273,7 +1289,95 @@ describe("cassandra Foreign-key arrays", function () {
});
});

it("03. Update record and remove one association - cassandra", function () {
it("03. Query rivers and filter associated cities on city_id existent in the fkarray: simple search - cassandra", function () {
// Operator: eq
let res = itHelpers.request_graph_ql_post(
`{
riversConnection(pagination:{first:2}) {
rivers{
river_id
citiesConnection(
pagination: {first: 2}
search: {field: city_id, value: "cassandra_city_1", operator: eq}
){
edges {
node {
city_id
}
}
}
}
}
}
`
);
expect(res.statusCode).to.equal(200);
let resBody = JSON.parse(res.body.toString("utf8"));
expect(resBody.data).to.deep.equal({"riversConnection":{"rivers":[{"river_id":"fkA_river_1","citiesConnection":{"edges":[{"node":{"city_id":"cassandra_city_1"}}]}}]}});


});

it("04. Query rivers and filter associated cities on city_id existent in the fkarray: complex search - cassandra", function(){
//Operator: in
let res = itHelpers.request_graph_ql_post(
`{
riversConnection(pagination:{first:2}) {
rivers{
river_id
citiesConnection(
pagination: {first: 2}
search: { operator: and, search:[
{field: city_id, value: "cassandra_city_2", operator: eq},
{field: name, value: "duesseldorf", operator: eq}
]}
){
edges {
node {
city_id
}
}
}
}
}
}
`
);
expect(res.statusCode).to.equal(200);
let resBody = JSON.parse(res.body.toString("utf8"));

expect(resBody.data).to.deep.equal({"riversConnection":{"rivers":[{"river_id":"fkA_river_1","citiesConnection":{"edges":[{"node":{"city_id":"cassandra_city_2"}}]}}]}});
});

it("05. Query rivers and filter associated cities on city_id existent in the fkarray: IN search - cassandra", function(){
//Operator: in
let res = itHelpers.request_graph_ql_post(
`{
riversConnection(pagination:{first:2}) {
rivers{
river_id
citiesConnection(
pagination: {first: 2}
search: {field: city_id, value: "cassandra_city_2,cassandra_city_1,city_non_existent", operator: in, valueType:Array}
){
edges {
node {
city_id
}
}
}
}
}
}
`
);
expect(res.statusCode).to.equal(200);
let resBody = JSON.parse(res.body.toString("utf8"));

expect(resBody.data).to.deep.equal({"riversConnection":{"rivers":[{"river_id":"fkA_river_1","citiesConnection":{"edges":[{"node":{"city_id":"cassandra_city_1"}},{"node":{"city_id":"cassandra_city_2"}}]}}]}})
});

it("06. Update record and remove one association - cassandra", function () {
let res = itHelpers.request_graph_ql_post(
'mutation{updateCity(city_id:"cassandra_city_1" removeRivers:["fkA_river_1"]){city_id river_ids}}'
);
Expand All @@ -1295,7 +1399,7 @@ describe("cassandra Foreign-key arrays", function () {
});
});

it("04. Update record and add one association - cassandra", function () {
it("07. Update record and add one association - cassandra", function () {
let res = itHelpers.request_graph_ql_post(
'mutation{updateRiver(river_id:"fkA_river_1" addCities:["cassandra_city_1"]){river_id city_ids}}'
);
Expand Down Expand Up @@ -1330,7 +1434,7 @@ describe("cassandra Foreign-key arrays", function () {
});
});

it("05. Update record and remove all association - cassandra", function () {
it("08. Update record and remove all association - cassandra", function () {
let res = itHelpers.request_graph_ql_post(
'mutation{updateRiver(river_id:"fkA_river_1" removeCities:["cassandra_city_1","cassandra_city_2"]){river_id city_ids}}'
);
Expand Down
6 changes: 6 additions & 0 deletions test/mocha_unit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2722,6 +2722,12 @@ describe("Cassandra storagetype", function () {
testCompare(generated_resolver, data_test.cassandra_resolver_Count);
});

it("targetStorageType cassandra fieldResolver Workaround - citiesConnection", async function () {
let opts = funks.getOptions(models_cassandra.river);
let generated_resolver = await funks.generateJs("create-resolvers", opts);
testCompare(generated_resolver, data_test.river_many_to_many_cassandra_fieldResolver_Connection);
});

it("cassandra models - constructor", async function () {
let opts = funks.getOptions(models_cassandra.city);
let generated_model = await funks.generateJs(
Expand Down
33 changes: 33 additions & 0 deletions test/unit_test_misc/data_models_cassandra.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,39 @@ module.exports.city = {
"internalId": "city_id"
}

module.exports.river = {
"model": "river",
"storageType": "SQL",
"attributes": {
"name": "String",
"length": "Int",
"river_id": "String",

"city_ids": "[String]"
},
"associations": {
"countries": {
"type": "many_to_many",
"implementation": "sql_cross_table",
"target": "country",
"sourceKey": "river_id",
"targetKey": "country_id",
"keysIn": "country_to_river",
"targetStorageType": "sql"
},
"cities": {
"type": "many_to_many",
"implementation": "foreignkeys",
"target": "city",
"targetStorageType": "cassandra",
"sourceKey": "city_ids",
"targetKey": "river_ids",
"keysIn": "river"
}
},
"internalId": "river_id"
}

module.exports.incident = {
"model": "Incident",
"storageType": "cassandra",
Expand Down
35 changes: 35 additions & 0 deletions test/unit_test_misc/test-describe/cassandra-storagetype.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,41 @@ countCities: async function({
}
`;

module.exports.river_many_to_many_cassandra_fieldResolver_Connection = `
river.prototype.citiesConnection = function({
search,
order,
pagination
}, context) {
//return an empty response if the foreignKey Array is empty, no need to query the database
if (!Array.isArray(this.city_ids) || this.city_ids.length === 0) {
return {
edges: [],
cities: [],
pageInfo: {
startCursor: null,
endCursor: null,
hasPreviousPage: false,
hasNextPage: false
}
};
}
const hasIdSearch = helper.parseFieldResolverSearchArgForCassandra(search, this.city_ids, models.city.idAttribute());
let nsearch = hasIdSearch ? search : helper.addSearchField({
"search": search,
"field": models.city.idAttribute(),
"value": this.city_ids.join(','),
"valueType": "Array",
"operator": "in"
});
return resolvers.citiesConnection({
search: nsearch,
order: order,
pagination: pagination
}, context);
}
`;

module.exports.cassandra_model_constructor = `
constructor(input) {
for (let key of Object.keys(input)) {
Expand Down
4 changes: 2 additions & 2 deletions views/create-migrations-cassandra.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module.exports = {
await cassandraClient.execute(createString);

let indexCreationPromises = indexCreationStrings.map(async i =>
await cassandraClient.execute('CREATE INDEX IF NOT EXISTS <%-namePl-%>_' + i + '_index ON <%-namePl-%> (' + i + ');'));
await cassandraClient.execute('CREATE INDEX IF NOT EXISTS <%-namePl-%>_' + i + '_index ON "<%-namePl-%>" ("' + i + '");'));

await Promise.allSettled(indexCreationPromises);

Expand All @@ -46,7 +46,7 @@ module.exports = {
// get the default cassandra client
const connectionInstances = await getConnectionInstances();
const cassandraClient = connectionInstances.get("default-cassandra").connection;
await cassandraClient.execute('DROP TABLE IF EXISTS <%-namePl-%>');
await cassandraClient.execute('DROP TABLE IF EXISTS "<%-namePl-%>"');
}

};
71 changes: 49 additions & 22 deletions views/create-resolvers.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,17 @@ const associationArgsDef = {
if (search === undefined || search === null) {
return resolvers.readOne<%=associations_one[i].target_cp%>({[models.<%=associations_one[i].target_lc-%>.idAttribute()]: this.<%=associations_one[i].targetKey%>},context)
} else {
<%# WORKAROUND FOR Cassandra targetStorageType:
In case of an association to a model within cassandra we need to do intersections
of the search parameters with the foreignkey array if the search is on the idAttribute
and with operator "eq" / "in", since cassandra doesn't support multiple restricions
with an "eq" / "in" on the primary key field. %>
<%if(associations_one[i].targetStorageType === 'cassandra'){%>
//WORKAROUND for cassandra targetStorageType. Mainpulate search to intersect Equal searches on the primaryKey
const hasIdSearch = helper.parseFieldResolverSearchArgForCassandra(search, this.<%=associations_one[i].targetKey%>, models.<%=associations_one[i].target_lc-%>.idAttribute());
<%}-%>
//build new search filter
let nsearch = helper.addSearchField({
let nsearch = <%if(associations_one[i].targetStorageType === 'cassandra'){%>hasIdSearch ? search : <%}-%>helper.addSearchField({
"search": search,
"field": models.<%=associations_one[i].target_lc-%>.idAttribute(),
"value": this.<%= associations_one[i].targetKey -%>,
Expand Down Expand Up @@ -260,13 +269,23 @@ const associationArgsDef = {
if (!Array.isArray(this.<%=associations_temp[i].sourceKey%>) || this.<%=associations_temp[i].sourceKey%>.length === 0 ) {
return 0;
}
let nsearch = helper.addSearchField({
<%# WORKAROUND FOR Cassandra targetStorageType:
In case of an association to a model within cassandra we need to do intersections
of the search parameters with the foreignkey array if the search is on the idAttribute
and with operator "eq" / "in", since cassandra doesn't support multiple restricions
with an "eq" / "in" on the primary key field. %>
<%if(associations_temp[i].targetStorageType === 'cassandra'){%>
//WORKAROUND for cassandra targetStorageType. Mainpulate search to intersect Equal searches on the primaryKey
const hasIdSearch = helper.parseFieldResolverSearchArgForCassandra(search, this.<%=associations_temp[i].sourceKey%>, models.<%=associations_temp[i].target_lc-%>.idAttribute());
<%}-%>
let nsearch = <%if(associations_temp[i].targetStorageType === 'cassandra'){%>hasIdSearch ? search : <%}-%>helper.addSearchField({
"search": search,
"field": models.<%=associations_temp[i].target_lc-%>.idAttribute(),
"value": this.<%=associations_temp[i].sourceKey%>.join(','),
"valueType": "Array",
"operator": "in"
});

<%}else{-%>
//build new search filter
let nsearch = helper.addSearchField({
Expand All @@ -293,26 +312,34 @@ const associationArgsDef = {
<%- nameLc -%>.prototype.<%=associations_temp[i].name%>Connection = function({search,order,pagination}, context){

<%if(associations_temp[i].assocThroughArray){%>
//return an empty response if the foreignKey Array is empty, no need to query the database
if (!Array.isArray(this.<%=associations_temp[i].sourceKey%>) || this.<%=associations_temp[i].sourceKey%>.length === 0 ) {
return {
edges: [],
<%=associations_temp[i].target_lc_pl%>: [],
pageInfo: {
startCursor: null,
endCursor: null,
hasPreviousPage: false,
hasNextPage: false
}
};
}
let nsearch = helper.addSearchField({
"search": search,
"field": models.<%=associations_temp[i].target_lc-%>.idAttribute(),
"value": this.<%=associations_temp[i].sourceKey%>.join(','),
"valueType": "Array",
"operator": "in"
});
//return an empty response if the foreignKey Array is empty, no need to query the database
if (!Array.isArray(this.<%=associations_temp[i].sourceKey%>) || this.<%=associations_temp[i].sourceKey%>.length === 0 ) {
return {
edges: [],
<%=associations_temp[i].target_lc_pl%>: [],
pageInfo: {
startCursor: null,
endCursor: null,
hasPreviousPage: false,
hasNextPage: false
}
};
}
<%# WORKAROUND FOR Cassandra targetStorageType:
In case of an association to a model within cassandra we need to do intersections
of the search parameters with the foreignkey array if the search is on the idAttribute
and with operator "eq" / "in", since cassandra doesn't support multiple restricions
with an "eq" / "in" on the primary key field. %>
<%if(associations_temp[i].targetStorageType === 'cassandra'){%>
const hasIdSearch = helper.parseFieldResolverSearchArgForCassandra(search, this.<%=associations_temp[i].sourceKey%>, models.<%=associations_temp[i].target_lc-%>.idAttribute());
<%}-%>
let nsearch = <%if(associations_temp[i].targetStorageType === 'cassandra'){%>hasIdSearch ? search : <%}-%>helper.addSearchField({
"search": search,
"field": models.<%=associations_temp[i].target_lc-%>.idAttribute(),
"value": this.<%=associations_temp[i].sourceKey%>.join(','),
"valueType": "Array",
"operator": "in"
});
<%}else{-%>

//build new search filter
Expand Down
Loading