kotolex / surrealist

Python library to work with SurrealDB
MIT License
21 stars 0 forks source link

How can i do one-to-one relationship? #60

Closed starascendin closed 1 day ago

starascendin commented 1 week ago

So i have something like this:

def create_one_suggested_cuts(suggested_cuts: SuggestedCuts) -> bool:
    db = srl_db_connect()
    suggested_cuts_dict = suggested_cuts.dict()
    print(suggested_cuts_dict)
    resp = db.table('suggested_cuts').create(f'`{suggested_cuts.video_id}`').content(suggested_cuts_dict).run()
    return resp.status == 'OK'

# suggested_cuts_dict
{
    'create_time': '2024-10-28T19:18:56.518Z',
    'update_time': '2024-10-28T19:18:56.518Z',
    'yt_video': 'yt_video:ZOCMS8j8jFQ',
    'video_id': 'ZOCMS8j8jFQ',
    'suggested_cuts': []
}

yt_video:ZOCMS8j8jFQ is a record in surrealdb, and when i create this suggested_cuts i want to link it to the said yt video. However, it shows up as string and not a surreal record. How can i link the two?

Thanks in advance, not sure if i missed this in the examples doc!

kotolex commented 1 week ago

Hey, I need more info

1) what is expected behavior for you? 2) how would you do it via CLI?

starascendin commented 6 days ago

so what i'm doing is to add surreal recordID like FK in another record, so in 'yt_video': 'yt_video:ZOCMS8j8jFQ' the yt_video:ZOCMS8j8jFQ is a recordID so i can refer to it. For some reason, the recordID became a string and thus loses the record linking capability.

W/ surreal's python sdk, you can achieve this so I was wondering if something in ur lib serialized it? Or at least it did if i use create.content.run method.

I also tried running the examples, and the ones w/ person:tobie didn't create the record as expected.

kotolex commented 5 days ago

@starascendin thanks again, I found the reason for this issue -it the same as for dates. SurrealDB do not perform any conversions, so when I send JSON or string it cant handle dates or records-ids, cause it looks like strings, so SDB interpret it as strings. For dates I was added explicit prefix d', now I had to create explicit RecordID object to properly works with IDS and send them in valid form.

Quote form docs: "As of v2.0.0, SurrealDB no longer eagerly converts a string into a record. An implicit r prefix or cast using (or <record>) is required instead."

I need some time for this fix, sorry for inconvenience

kotolex commented 5 days ago

@starascendin "I also tried running the examples, and the ones w/ person:tobie didn't create the record as expected." can u give me an example or link to it? I want to fix all issues at once

starascendin commented 3 days ago
from surrealist import Database

with Database("http://127.0.0.1:8083", 'testdb', 'testdb', credentials=("test", "test")) as db:
    print(db.tables())  # [] cause database is empty
    table = db.table("person")  # even there is no such table yes it is OK to switch on it
    print(table.count())  # and even get count of records which is 0 for non-existent table
    # now let's create one record via set statement
    result = table.create().set(id="alex001", name="Alex", age=30, active=True).run()  # pay attention how we use keyword parameters
    print(result.result)  # [{'active': True, 'age': 30, 'id': 'person:wfulrb7dqml3vv7koqnb', 'name': 'Alex'}]
    # now let's create one record via python dict
    result = table.create().content({'id': "jane001", 'name': "Jane", 'age': 22, 'active': True, 'friend': 'person:alex001'}).run()  # dict now
    print(result.result)  # [{'active': True, 'age': 22, 'id': 'person:x57n30x0n0sd104y235k', 'name': 'Jane'}]

    # let's check all it really in table, we use select all
    result = table.select().run()
    # [{'active': True, 'age': 22, 'id': 'person:84iakx5ptoeljoc4hv07', 'name': 'Jane'},
    # {'active': True, 'age': 30, 'id': 'person:8vivzq48kof6bg5dlc7a', 'name': 'Alex'}]
    print(result.result)
    result = table.select('*').run()  # same result if we use '*'
    print(result.result)
select * from person;

[
    {
        active: true,
        age: 30,
        id: person:alex001,
        name: 'Alex'
    },
    {
        active: true,
        age: 22,
        friend: 'person:alex001',
        id: person:jane001,
        name: 'Jane'
    }
]

So in jane, there should be a link to person:alex001 for friend field. In surrealsdk i think you can use a string and it does the linking

kotolex commented 2 days ago

@starascendin please update to 1.0.5 Now you should use RecordId wrapper for all record_id which you want to use in query

Here is the code

from surrealist import Surreal, RecordId, Database

surreal = Surreal("http://127.0.0.1:8000", credentials=("root", "root"))
with surreal.connect() as ws_connection:
    ws_connection.use("test", "test")
    db = Database.from_connection(ws_connection)
    author_id = RecordId("john", table="author")  # here we create an author id
    res = db.author.create(author_id).content({"name": "johnny cash", "age": 30}).run()  # add an author with id
    print(res.result)  # [{'age': 30, 'id': 'author:john', 'name': 'johnny cash'}]
    # now we create a book linked to this author, note how we use record_id in dict
    res = db.book.create().content({"title": "The Book", "isbn": None, "author": author_id}).run()
    book_id = res.id  # get the id of the book, but it is a string, we should wrap it to use via a library
    print(res.result)  # [{'author': 'author:john', 'id': 'book:fy51pzmi9ka2taxmtb7z', 'isbn': None, 'title': 'The Book'}]
    # here you can see a link is workinig, because we query not only book, but author properties too
    res = db.book.select("title, author.name, author.age").run()
    print(res.result)  # [{'author': {'age': 30, 'name': 'johnny cash'}, 'title': 'The Book'}]
    # we can select author by id
    res = db.author.select("name, age").by_id(author_id).run()
    print(res.result)  # [{'age': 30, 'name': 'johnny cash'}]
    # we can select a book by id, but note-we wrap it to RecordId
    res = db.book.select().by_id(RecordId(book_id)).run()
    print(res.result)  # [{'author': 'author:john', 'id': 'book:fy51pzmi9ka2taxmtb7z', 'isbn': None, 'title': 'The Book'}]

and after that via CLI

` test/test> select * from author [[{ age: 30, id: author:john, name: 'johnny cash' }]]

test/test> select * from book [[{ author: author:john, id: book:fy51pzmi9ka2taxmtb7z, isbn: NULL, title: 'The Book' }]]

test/test> `

kotolex commented 2 days ago

I am waiting for your tests and thank you for your time and patience!

P.S. if you have no time (while I am fixing bugs) you always can generate valid string query and use it with connection.query() method

starascendin commented 1 day ago

let me test

starascendin commented 1 day ago

CleanShot 2024-11-06 at 19 25 59@2x

this is working now. Thanks for your work!!!!