Giter VIP home page Giter VIP logo

memgraph / gqlalchemy Goto Github PK

View Code? Open in Web Editor NEW
207.0 11.0 26.0 2.42 MB

GQLAlchemy is a library developed with the purpose of assisting in writing and running queries on Memgraph. GQLAlchemy supports high-level connection to Memgraph as well as modular query builder.

Home Page: https://pypi.org/project/gqlalchemy/

License: Apache License 2.0

Python 99.88% Cypher 0.12%
python graphs memgraph networkx object-graph-mapper ogm query-builder schema-validation graph-database neo4j neo4j-client

gqlalchemy's Introduction

GQLAlchemy

Code style: black

GQLAlchemy is a fully open-source Python library and Object Graph Mapper (OGM) - a link between graph database objects and Python objects.

An Object Graph Mapper or OGM provides a developer-friendly workflow that allows for writing object-oriented notation to communicate with graph databases. Instead of writing Cypher queries, you will be able to write object-oriented code, which the OGM will automatically translate into Cypher queries.

Installation

Prerequisites

Warning

Python 3.11 users: On Windows, GQLAlchemy is not yet compatible with this Python version. Linux users can install GQLAlchemy without the DGL extra (due to its dependencies not supporting Python 3.11 yet). If this is currently a blocker for you, please let us know by opening an issue.

Install GQLAlchemy

After you’ve installed the prerequisites, run the following command to install GQLAlchemy:

pip install gqlalchemy

With the above command, you get the default GQLAlchemy installation which doesn’t include import/export support for certain formats (see below). To get additional import/export capabilities, use one of the following install options:

pip install gqlalchemy[arrow] # Support for the CSV, Parquet, ORC and IPC/Feather/Arrow formats
pip install gqlalchemy[dgl] # DGL support (also includes torch)
pip install gqlalchemy[docker] # Docker support

pip install gqlalchemy[all] # All of the above

If you intend to use GQLAlchemy with PyTorch Geometric support, that library must be installed manually:

pip install gqlalchemy[torch_pyg] # prerequisite
pip install torch-scatter torch-sparse torch-cluster torch-spline-conv torch-geometric -f https://data.pyg.org/whl/torch-1.13.0+cpu.html"

If you are using the zsh terminal, surround gqlalchemy[$extras] with quotes:

pip install 'gqlalchemy[arrow]'

If you are using Conda for Python environment management, you can install GQLAlchemy through pip.

Build & Test

The project uses Poetry to build the library. Clone or download the GQLAlchemy source code locally and run the following command to build it from source with Poetry:

poetry install --all-extras

The poetry install --all-extras command installs GQLAlchemy with all extras (optional dependencies). Alternatively, you can use the -E option to define what extras to install:

poetry install # No extras

poetry install -E arrow # Support for the CSV, Parquet, ORC and IPC/Feather/Arrow formats
poetry install -E dgl # DGL support (also includes torch)
poetry install -E docker # Docker support

To run the tests, make sure you have an active Memgraph instance, and execute one of the following commands:

poetry run pytest . -k "not slow" # If all extras installed

poetry run pytest . -k "not slow and not extras" # Otherwise

If you’ve installed only certain extras, it’s also possible to run their associated tests:

poetry run pytest . -k "arrow"
poetry run pytest . -k "dgl"
poetry run pytest . -k "docker"

Development (how to build)

poetry run flake8 .
poetry run black .
poetry run pytest . -k "not slow and not extras"

Documentation

The GQLAlchemy documentation is available on GitHub.

The reference guide can be generated from the code by executing:

pip3 install pydoc-markdown
pydoc-markdown

Other parts of the documentation are written and located at docs directory. To test the documentation locally execute:

pip3 install mkdocs
pip3 install mkdocs-material
pip3 install pymdown-extensions
mkdocs serve

License

Copyright (c) 2016-2023 Memgraph Ltd.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

gqlalchemy's People

Contributors

aalekhpatel07 avatar alex-linx avatar antepusic avatar antoniofilipovic avatar as51340 avatar boristasevski avatar brunos252 avatar dadevel avatar g-despot avatar gitbuda avatar insectatorious avatar jbajic avatar jmatak avatar josipmrden avatar jsoref avatar katarinasupe avatar kgolubic avatar lcorcodilos avatar mastermedo avatar niko4299 avatar utkarsh299-tech avatar vedranmiletic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gqlalchemy's Issues

Create index on node label

Currently, we have index only on properties and we should add indexes on labels.

We have
CREATE INDEX ON :Person(age);
and that is done with the help of Field on the property, where we have index=True.

but we don't have:
CREATE INDEX ON :Person;
and that should be done with the index attribute on class definition probably.

Add triggers control

Currently, there is no easy way to create/update/delete triggers using gqlalchemy except using execute.

[ENHANCEMENT] add simpler use of return in query builder

Describe the bug

As @katarinasupe mentioned here: #139 (comment),
when using return clause, if we are not using AS keyword, we still need to pass a dictionary, so for some of the most basic use cases to write RETURN n we need to construct call query builder like:
.return_({"n": ""})

Expected behavior

It would be better if we could just write .return_("n") the argument being either of type string or Dict.

Hacktoberfest 2021 - Fix a bug, improve a feature or add something new!

memgraph-hacktoberfest

For a meaningful contribution, get a Memgraph Hacktoberfest T-shirt!

You can fix bugs or provide better implementations for certain features! Feel free to inform the community by filling an issue and start hacking. If you're new to contributing code, please read our Contribution Guidelines for an overall understanding.

Discord

Memgraph has repositories with different programming languages and technology stacks, so find what works for you and start coding there:

  • MAGE - graph algorithm library (C or C++ or Python or Rust).
  • Memgraph - graph streaming platform for C/C++ wizards.
  • GQLAlchemy - object graph mapper (OGM) written in Python.

If you want to contribute to any other of our repositories, just follow the same principle and open an issue. We will handle the rest.

What can you do to participate?

  1. Read our Contribution Guidelines.
  2. Comment below or open an issue (for big ideas you may want the community to know) on your new implementations, fixes, or functionalities.
  3. Start hacking!
  4. Open a pull request for your contribution.
  5. Wait until your pull requests get reviewed or merged! In the meantime, you can review someone else's pull requests too.

Remarks

  • Join our Discord server to get started. It's definitely easier with the help of the Memgraph engineering team or other community members.
  • As part of the event, we would like to invite everyone to adhere to Hacktoberfest's values and our Code of Conduct.
  • Please observe Hacktoberfest's rules, terms, and FAQ. If a pull request is marked invalid or spam it would not be counted, and the person may be disqualified from the event.
  • Hacktoberfest 2021 is an event presented by DigitalOcean, Intel, appwrite, and deepsource.

[BUG] The function `to_cypher_value()` doesn't work with `datetime.date`

When calling the function to_cypher_value() with a datetime.date object, the function will throw the following error:

~/anaconda3/lib/python3.9/site-packages/gqlalchemy/utilities.py in to_cypher_value(value, config)
     67         return "null"
     68 
---> 69     if value.lower() in ["true", "false"]:
     70         return value
     71 

AttributeError: 'datetime.date' object has no attribute 'lower'

[ENHANCEMENT] Should `Memgraph.new_connection` be a private method?

Describe the bug
My first thoughts were that Memgraph.new_connection() will give me a new Memgraph connection with the type of Memgraph so I can continue running new queries.
I had a case where I have a connection to Memgraph as an admin user and I wanted to have a new connection to the same Memgraph, but as another user and I expected to have something like this:

admin_mg = Memgraph('127.0.0.1', 7687, username='admin', password='admin)
admin_mg.execute('<Cypher query ... >')

# it will use `host` and `port` from the main class, not the auth data because of security concerns
user_mg = admin_mg.new_connection(username='user', password='user)
user_mg.execute('<Cypher query .... >')

But then I saw that new_connection() returns a baseline Connection object that is no use for me.

Expected behavior
Should Memgraph.new_connection be a private method (it is used within Memgraph private methods)? If there will be something like new_connection that is a public method, it should return an object of type Memgraph then.

[BUG] to_cypher_value badly converts numpy objects

GQLAlchemy version 1.3.2

Describe the bug When converting NetworkX graph to cypher queries, if the graph is populated with numpy objects the utility method to_cypher_value makes wrong conversions for numpy objects(arrays)

Expected behavior numpy array gets converted as array

Steps to reproduce

graph = nx.Graph()
graph.add_nodes_from([
    (1, {"Key": np.array(["Value1", "Value2"], dtype=object)}),
]
)

cypher = nx_to_cypher(graph)

print (list(cypher)[0])

Expected result
CREATE ( {Key: ['Value1', 'Value2'], id: 1});

Actual result
CREATE ( {Key: '['Value1' 'Value2']', id: 1});

Error using datetime

Hi,

I am new to this lib and I played around with timestamps in my graph.

When I run my example below I get the following error:

gqlalchemy\connection.py", line 92, in execute_and_fetch
    cursor.execute(query)
mgclient.DatabaseError: Function 'datetime.datetime' doesn't exist.

I tested it with gqlalchemy 1.3.1.

Example:

from datetime import datetime
from gqlalchemy import Memgraph, Node, Relationship, Field

class User(Node):
    id: str = Field(index=True, unique=True, db=db)
    name: str = Field()
    timestamp: datetime = Field()

User(id="1", name="myUser", timestamp=datetime.now()).save(db)

After running into this error I did a little bit of debugging.
I printed the underlying cypher statement:

MATCH (node: User) WHERE  node.id = '1'  RETURN node;
CREATE (node:User)   SET node.id = '1'  SET node.name = 'myUser'  SET node.timestamp = datetime.datetime(2022, 7, 24, 0, 32, 51, 583238)  RETURN node;

Here one can see 'datetime.datetime(2022, 7, 24, 0, 32, 51, 583238)'. This seems to be the datetime object representation instead of 'localDateTime(...)'. See:

assert to_cypher_value(localdatetime) == "localDateTime('1999-12-12T12:12:12')"

I also found out that 'to_cypher_value(...)' is never called in my case.

If I switch the type to 'str' instead of 'datetime' I do not get any error.

Btw., nice lib :-)!

BR,
Alexander

GQLAlchemy can't be installed with Python 3.10 on Windows

Currently, GQLAlchemy can't be installed with Python 3.10 on Windows, since its dependencies still do not support Python 3.10. For example, GQLAlchemy has NetworkX as a dependency and it has numpy as its dependency. There is no version of numpy that works with Python 10 on Windows. Once all dependencies are supported for Python 3.10, we can update the appropriate packages and add Python 3.10 support for Windows.

[ENHANCEMENT] Make type hints more permissive

At our company we are big fans of type hints to ensure code quality. At the very least in some instances tpye hints could be more permissive here. e g. for node labels we have among others List[str], looking at the implementation, we could allow all Iterable[str]. in this sepcific case we are heavily working with sets and set semantics. to enable type checks in CI/CD we would then have to convert all sets passed as labels to lists, just to make type checkers happy :)

[ENHANCEMENT] Make host and port readonly properties on Memgraph object

Describe the bug
It would be great to be able to read host and port after the init of the Memgraph object, e.g.

memgraph = Memgraph('127.0.0.1', 7687)

memgraph.host  # '127.0.0.1'
memgraph.port  # 7687

Expected behavior
Properties host and port read-only properties. All other init parameters should be kept private (e.g. username, password).
happen.

Load() doesn't work without default or Optional

It would be great that the load() method works if we add only one property upon which object in Memgraph is found.

For example, let's say we have defined Stream class like this:

class Stream(Node, labels={"User", "Stream"}):
    name: str = Field(index=True, unique=True, db=memgraph, label="User")
    id: str = Field(index=True, unique=True, db=memgraph)
    url: str = Field()
    followers: int = Field()
    createdAt: str = Field()
    totalViewCount: int = Field()
    description: str = Field()

Now, let's suppose I want to find a streamer based on its id (which is unique). I expect that stream = Stream(id="7").load(db=memgraph) returns Stream whose id is "7". That does not work, because it's expected that I give value for all properties of class Stream. This can be solved by adding default value ("") to each property, or by using Optional for now.

OGM migrations

@jbajic, I've seen the OGM is on the roadmap and I wanted to propose that we also design a migration system for it, similar to Alembic. Given that property graphs have a dynamic schema, this could help make the projects more maintainable and help with data consistency issues across project versions.

Leave out the internal ids when creating a relationship

When creating a relationship it would be great if we didn't have to use internal ids like here:

speaks_rel = Speaks(
    _start_node_id = stream._id,
    _end_node_id = language._id
).save()

Then the code would look like this:

speaks_rel = Speaks(
    _start_node_id = stream,
    _end_node_id = language
).save()      

Then _start_node_id would reference the whole node. The future problem is that if the internal ids of nodes were changed, then the relationship between them wouldn't exist anymore.

Related:
#30

[ENHANCEMENT] Have a way to wait for active connection

Describe the bug
My application was starting Memgraph via Docker dynamically and then connecting to it to set up the initial state (indexes, users, datasets). After Docker is successfully up and running, Memgraph is not immediately listening to bolt protocol and my queries were failing because of an inactive connection.
I created a workaround that is waiting for an active connection before proceeding with other queries. Maybe it makes sense to integrate or to have something similar as part of the Memgraph object.

from time import sleep

def wait_for_connection(memgraph: Memgraph, max_tries: int = 10, wait_sec: float = 1) -> None:
    if max_tries == 0:
        raise Exception('Failed to connect to running Memgraph')
    try:
        list(memgraph.execute_and_fetch('MATCH (n) RETURN n LIMIT 1'))
    except Exception as e:
        # TODO: Replace Exception with GQLAlchemyError (connection error) when gqlalchemy will raise
        # GQLAlchemyError or GQLAlchemyConnectionError
        if 'failed to receive handshake response' not in str(e) and 'failed to send handshake data' not in str(e):
            raise e
        sleep(wait_sec)
        wait_for_connection(memgraph, max_tries=max_tries - 1, wait_sec=wait_sec)

memgraph = Memgraph('127.0.0.1', 7687)
wait_for_connection(memgraph)

memgraph.execute('<Cypher query ... >')

Expected behavior
To have a way to wait for an active connection. Maybe it makes sense to have the fallback (connection retry) option for every execute and execute_and_fetch if Memgraph is not up and running?

The issue with handling Exception vs GQLAlchemyError is also reported as another Github issue.

Arguments in where method

The where method has the argument property, which can actually be a variable, because you can use the WHERE clause to filter by labels, not only by properties. Maybe rename the argument to a more generic name (item). Also, when using .where("node", ":", "Stream"), it automatically creates spaces -> node : Stream, and that is not common for Cypher.

Example usage:

CALL pagerank.get()
YIELD node, rank
WITH node, rank
WHERE node:Stream OR node:User
RETURN node, rank
ORDER BY rank DESC
LIMIT 50;
Call("pagerank.get").yield_()
  .with_(
      {"node": "node", "rank": "rank"}
  ).where("node", ":", "Stream")
  .or_where("node", ":", "User")
  .return_({"node": "node", "rank": "rank"})
  .order_by("rank DESC")
  .limit(
      50
)

Bootstrap servers should be list of escaped strings

Bootstrap servers are currently one string that is not escaped. Example:

stream = MemgraphKafkaStream(
    name="chatter_stream",
    topics=["chatters"],
    transform="twitch.chatters",
    bootstrap_servers="'kafka:9092'",
)

It should look like this:

stream = MemgraphKafkaStream(
    name="chatter_stream",
    topics=["chatters"],
    transform="twitch.chatters",
    bootstrap_servers=["kafka:9092","hehe:17"],
)

Creating constraints on multiple label classes

When creating a node with multiple labels:

db = Memgraph()


class User(Node):
    id: int = Field(unique=True, db=db)

class Streamer(Node, _node_labels={"User", "Streamer"}):
    streamer_id: int = Field(unique=True, db=db)

This should throw an error, because we can't know if the Streamer.streamer_id should create a uniqueness constraint on the label Streamer or on the label User, because a streamer has two labels. In this case the user will get the following message:

GQLAlchemyMultipleLabelConstraintError:
    Please specify a label(s) for the constraint should be executed on:
    Example:
        class Streamer(Node, _node_labels={"User", "Streamer"}):
            streamer_id: int = Field(unique=True, _label="Streamer", db=Memgraph())

Escaping properties

There is no proper way to set match parameters, only inserting using formatted text, and then I have to take care of the way those properties will look in query, will they have quotes, escaped... This should be automated.
e.g.
memgraph.execute(CREATE (: {{name: {name}, age: {age} }})
I have to manually call to_cypher_properties_function on these. Find a proper way to pass any kind of parameters.

Add query module control

Calling query modules and fetching results should come as a nice addition to both gqlalchemy and MAGE

Add more clauses for starting queries

Currently, to start building a query, aside from QueryBuilder() we can also start with:
call = Call
create = Create
match = Match
merge = Merge
unwind = Unwind
with_ = With

for instance, create().node()...

Issue is: we should add more of them, load_csv, foreach...

Indexes only work if NetworkX ids are integers

_create_node and _create_edge accept only integers as ids (nx_id, from_id, to_id). The ids could be, e.g., strings. Graphviz Python libraries create node ids that are integers. If ids are not integers it's impossible to generate valid Memgraph queries.

Take a look here (How to analyze Python, Cpp and Rust dependencies? PART 2) to see the details about the problem. The solution was to use gqlalchemy as a library and reuse some of the functions, but it's definitely possible to push all the required capabilities into gqlalchemy.

[BUG] Instantiating `Merge` class fails

Describe the bug

In the line below, MergePartialQuery is invoked with optional argument, but class constructor does not accept arguments.

self._query.append(MergePartialQuery(optional))

To Reproduce Steps to reproduce the behavior:

from gqlalchemy import merge

merge()

Expected behavior

no exception when instantiating class :)

Rename edge_label to edge_type

I noticed that to() method in query builder has argument edge_label for relationship type.

 def to(
        self,
        edge_label: Optional[str] = "",
        directed: Optional[bool] = True,
        variable: Optional[str] = None,
        relationship: Optional["Relationship"] = None,
        **kwargs,
    ) -> "DeclarativeBase":

I know there was a discussion because whether to name it type. Type is not a reserved keyword in Python, but it is still not wise to use it. Hence, I would suggest edge_type.

Edit:
When I think about it more, it should be named relationship or relationship_type, since we are not using edge in our codebase.

[BUG] All exceptions should be a subclass of GQLAlchemyError

Memgraph version
Docker: memgraph/memgraph-mage:1.1.1

Describe the bug
I wanted to check if my connection is alive or not by running a test query with the following code, but the exception that I am receiving from memgraph.execute_and_fetch is not of a class GQLAlchemyError but an internal mgclient error which makes catching errors from gqlalchemy really hard.

# Initial idea, not working
def is_connection_ready(memgraph: Memgraph) -> bool:
    try:
        list(memgraph.execute_and_fetch('MATCH (n) RETURN n LIMIT 1'))
        return true
    except GQLAlchemyError as e:
        return false

Exceptions from mgclient that I am receiving are:

  • mgclient.OperationalError: failed to receive handshake response or
  • mgclient.OperationalError: failed to send handshake data

The only workaround that is working for me is the following (which is not a good practice):

# Workaround that is working, but dirty hacking
def is_connection_ready(memgraph: Memgraph) -> bool:
    try:
        list(memgraph.execute_and_fetch('MATCH (n) RETURN n LIMIT 1'))
        return true
    except Exception as e:
        # As we can't filter out ConnectionError, check the error message
        if 'failed to receive handshake response' not in str(e) and 'failed to send handshake data' not in str(e):
            raise e
        return false

When doing a dirty workaround, I am seeing the following message in the STDERR (probably internal output from mgclient) which I am not sure how to disable.

mg_raw_transport_recv: connection closed by server

Expected behavior
I am expecting all exceptions from gqlachemy to be a subclass of GQLAlchemyError to make it easy to catch by class type.

Schema creation and validation

Memgraph is schemaless, but some use-cases require strict validation rules. Instead of enforcing the schema in Memgraph, the user should be able to enforce it easily in GQLAlchemy. With pydantic we should be able to add schema validation to the graph objects.

Streaming support via websocket

Memgraph is a streaming graph analytics platform. That means it can send the information back to the client asynchronously. GQLAlchemy should be able to hook on to those ports and listen for updates.

[BUG] Non-Printable Characters Lead to 'Invalid query'

Memgraph version 2.3.1
GQLAlchemy 1.3.1

Describe the bug
Non-printable characters like '\x13' lead to 'Invalid query'

To Reproduce

from gqlalchemy import Memgraph, Node, Field

db = Memgraph()

class Test(Node):
    name: str = Field()

Test(name='\x13').save(db)

Expected behavior The str is properly sanitized/escaped or the query 'just works'.

Logs

CREATE (node:Test)   SET node.name = '\x13'  RETURN node;
---
gqlalchemy\connection.py", line 93, in execute_and_fetch
    cursor.execute(query)
mgclient.DatabaseError: Invalid query.

Additional context I have raw data that I want to load into my graph. Some of my statements fail due to the error above. The error message is not very helpful so I had to debug a bit.
I think it could be in the scope of this project to do escaping/sanitizing of non-printable characters, or maybe it is a bug in memgraph itself (Python does not throw any error if I print \x13 :-) ).

At least the error message needs some improvements and more context. Maybe you could print/log the query in case of an error?
I also think it would be nice to feature toggle query logging in general.

BR,
Alexander

Getting Node object from Edge

When I am working with an Edge, there is a scenario where I want to find which Node is it, and I only have Memgraph node ID, and not the whole object. And I would want further to make a query with those Nodes I got from Edge property, but I can't as I can't make a query towards database with Memgraph ID of Node.

In other words, it would be good to return Node instead of Node-id in Memgraph when calling edge.start_node or edge.end_node

Create custom OGM fields instead of primitive types

Instead of using primitive types for fields of GraphObject subclasses, we can create custom fields that will make it possible to create automatic indexing and/or writing properties to disk, etc.

instead of writing:

class Person(Node):
    ssn: str
    avatar: Image

the user will be able to write:

class Person(Node):
    ssn: Property(str, index=True)
    avatar: Property(Image, on_disk=True)

Add the possibility of partial loading

Related to the discussion at #79.

Suppose we have a node defined:

class Stream(Node, labels={"User", "Stream"}):
    name: str = Field(index=True, unique=True, db=memgraph, label="User")
    id: str = Field(index=True, unique=True, db=memgraph)
    url: str = Field()
    followers: int = Field()
    createdAt: str = Field()
    totalViewCount: int = Field()
    description: str = Field()

And that we want to load all nodes that have followers = 500 from the database.

Something like:

streamers = memgraph.load_node_partial(Stream(followers=500))

Then streamers would be a list of all Stream nodes that have property followers set to 500.
Then it won't be important that other properties are Optional and it is possible to get a list of matching streamers.

Add optional dependency installation

Add the possibility to choose which dependencies to install and which not, when installing GQLAlchemy.

For example, pip install gqlalchemy installs all dependencies, and we define extra dependencies that don't have to be installed necessarily for basic GQLAlchemy usage. For example, docker, networkx and neo4j would be extra dependencies. If you want to install them, you would run something like:

pip install gqlachemy [all]

or for just one extra dependency:

pip install gqlalchemy [docker]

and for more than one extra dependency:

pip install gqlalchemy [docker, networkx]

[BUG] : Fix typo

Describe the bug A clear and concise description of what the bug is.

I found a spelling error of tests in Build & Test while going through the README.md. The line goes something like: Before running tets...
For reference, I have attached a screenshot of the same.
Screenshot (378)

Properties should be inherited

If I don't add property name to the class Stream, like this:

class User(Node):
    name: str = Field(index=True, unique=True, db=memgraph)


class Stream(User):
    id: str = Field(index=True, unique=True, db=memgraph)

then I get the following error:

twitch-app_1     |   File "/app/models.py", line 10, in <module>
twitch-app_1     |     class Stream(User):
twitch-app_1     |   File "/usr/local/lib/python3.8/site-packages/gqlalchemy/models.py", line 314, in __new__
twitch-app_1     |     raise GQLAlchemyDatabaseMissingInFieldError(
twitch-app_1     | gqlalchemy.exceptions.GQLAlchemyDatabaseMissingInFieldError

I expected that the name property would be inherited.

This works for now:


class User(Node):
    name: str = Field(index=True, unique=True, db=memgraph)


class Stream(User):
    name: Optional[str] = Field(index=True, unique=True, db=memgraph, label="User")
    id: str = Field(index=True, unique=True, db=memgraph)

No support for setting node (or relationship) property to a variable value

Describe the bug
In the Cypher grammar, node and relationship properties are defined as:
mapLiteral : '{' ( propertyKeyName ':' expression ( ',' propertyKeyName ':' expression )* )? '}' ;
where the expression can be a variable, but we do not have this support.
Because of this, it is not possible to make this partial query:
CREATE (n {prop: var}), where var is a variable.
To make it, we would write something like:
.create().node(variable="n", prop="var") and var would be passed as a string; prop: "var"

This is particularly necessary for FOREACH clause, for instance:
FOREACH ( i IN [1, 2, 3] | CREATE (n {id: i}) )

Allow bootstrap_servers argument usage without quotes

When creating a stream, the bootstrap_servers argument needs to be specified with quotes around it:

stream = MemgraphKafkaStream(
    name="ratings_stream",
    topics=["ratings"],
    transform="movielens.rating",
    bootstrap_servers="'kafka:9092'",
)
memgraph.create_stream(stream)

This can sometimes be misleading and users will maybe pass a plain string without the additional quotes. Both options need to be handled in the background and adjusted to the proper Cypher syntax.

Additionally, passing multiple bootstrap servers should be allowed in the form of a list of strings:

stream = MemgraphKafkaStream(
    name="ratings_stream",
    topics=["ratings"],
    transform="movielens.rating",
    bootstrap_servers=["kafka:9092", "kafka:9093"],
)
memgraph.create_stream(stream)

Property without Field() shouldn't be saved into Memgraph

A property without Field() shouldn't be saved into Memgraph.
Example: tests/ogm/without_field_test.py
The followers property shouldn't be saved into Memgraph.

Mislav's suggestion -> we can make Node and Relationship class an exception because we want to be able to create a Node with Node(id=7, _label="Stream") and we want that the id property is saved into Memgraph.

Then loading like he suggested previously (#79) should work, that is, the test beb7519 should pass.

[Build system] Second Windows Test Run fails

Second Build and Test / build_and_test_windows (almost?) always fails.

By second i mean whichever Build and Test for windows runs first it will complete, and the second one will time-out, almost every time

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.