Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About Relations (associations, association_meta) #385

Open
IngwiePhoenix opened this issue Feb 16, 2025 · 1 comment
Open

About Relations (associations, association_meta) #385

IngwiePhoenix opened this issue Feb 16, 2025 · 1 comment

Comments

@IngwiePhoenix
Copy link

Hey there!

About a weekend and some later, and I am much more confident in my driver - I feel like it's maturing, and so is the accompaning REL implementation. So, I have started to write some playground-style tests to see how far it works ... or does not.

Right now, I am trying to get related record loading to work; so let me give you the TL;DR:

DEFINE TABLE users SCHEMAFULl;
DEFINE FIELD name ON users TYPE string;
DEFINE FIELD tags ON users TYPE array<string>;
DEFINE FIELD photos ON users TYPE record<photos>;

DEFINE TABLE photos SCHEMAFULL;
DEFINE FIELD title ON photos TYPE string;
DEFINE FIELD file ON photos TYPE bytes;

That's a very basic 1:n relation. To query all users, with their photos:

SELECT * FROM users FETCH photos;

The resulting JSON will also contain the photos - as already attached objects.

{
    "id": "user:test",
    "name": "Test User",
    "tags": ["dev", "nerd"],
    "photos": [
        {
            "id": "photos:abcdef",
            "title": "A selfie",
            "data": [...]
        },
        {
            "id": "photos:zyxvut",
            "title": "Another selfie",
            "data": [...]
        }
    ]
}

This obviously isn't how the big classics, MySQL and PostgresQL behave.

The way the driver handles it, is that it returns both tags and photos as []byte.

This is demonstrated here. Unfortunately, inserting data does not work: Found NONE for field risks_rel, with record processes:Lohnabrechnung2, but expected a record<risks>. That's a SurrealDB error, and here is the query that produced that:

surrealdb:driver:connection:execWithArgs INSERT INTO processes (title, description, responsible, risks, storage, id, created_at, updated_at, legal_basis, tasks, affected_data) VALUES ($_1, $_2, $_3, $_4, $_5, $_6, $_7, $_8, $_9, $_10, $_11) ON DUPLICATE KEY UPDATE storage = $_12, title = $_13, description = $_14, responsible = $_15, risks = $_16, tasks = $_17, affected_data = $_18, id = $_19, created_at = $_20, updated_at = $_21, legal_basis = $_22;
surrealdb:driver:connection:execWithArgs map[string]interface {}{
surrealdb:driver:connection:execWithArgs     "_1":  "Lohnabrechnung",
surrealdb:driver:connection:execWithArgs     "_10": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Einholen der Bankdaten"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_11": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Kontoinformationen"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_12": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"NAS", "Aktenschrank"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_13": "Lohnabrechnung",
surrealdb:driver:connection:execWithArgs     "_14": "Beispiel der Lohnabrechnung",
surrealdb:driver:connection:execWithArgs     "_15": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Alex", "Daniel"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_16": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Datendiebstahl", "Ausnutzung"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_17": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Einholen der Bankdaten"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_18": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Kontoinformationen"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_19": "Lohnabrechnung2",
surrealdb:driver:connection:execWithArgs     "_2":  "Beispiel der Lohnabrechnung",
surrealdb:driver:connection:execWithArgs     "_20": "d'2025-02-16T02:10:20+01:00'",
surrealdb:driver:connection:execWithArgs     "_21": "d'2025-02-16T02:10:20+01:00'",
surrealdb:driver:connection:execWithArgs     "_22": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"GOB", "Wirtschaft"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_3": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Alex", "Daniel"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_4": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"Datendiebstahl", "Ausnutzung"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_5": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"NAS", "Aktenschrank"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs     "_6": "Lohnabrechnung2",
surrealdb:driver:connection:execWithArgs     "_7": "d'2025-02-16T02:10:20+01:00'",
surrealdb:driver:connection:execWithArgs     "_8": "d'2025-02-16T02:10:20+01:00'",
surrealdb:driver:connection:execWithArgs     "_9": surrealtypes.ArrayOf[string]{
surrealdb:driver:connection:execWithArgs         Values: {"GOB", "Wirtschaft"},
surrealdb:driver:connection:execWithArgs     },
surrealdb:driver:connection:execWithArgs }

(I have some actually usable debug logging now...it helps a lot.)

The actual struct being passed is:

	lohnabrechnung := Process{
		ID:           "Lohnabrechnung2",
		Title:        "Lohnabrechnung",
		Description:  "Beispiel der Lohnabrechnung",
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
		Responsible:  st.ArrayOf[string]{Values: []string{"Alex", "Daniel"}},
		LegalBasis:   st.ArrayOf[string]{Values: []string{"GOB", "Wirtschaft"}},
		Risks:        st.ArrayOf[string]{Values: []string{"Datendiebstahl", "Ausnutzung"}},
		Storage:      st.ArrayOf[string]{Values: []string{"NAS", "Aktenschrank"}},
		Tasks:        st.ArrayOf[string]{Values: []string{"Einholen der Bankdaten"}},
		AffectedData: st.ArrayOf[string]{Values: []string{"Kontoinformationen"}},
		RelatedRisks: []Risk{ // <--- This does not get sent!
			{Title: "Beispiel", Description: "Beschreibungszeug"},
			{Title: "Beispiel 2", Description: "Beschreibungszeug 2"},
		},
	}

Is there any interface I can implement in my adapter to work with/around that?

Thank you and kind regards,

Ingwie

@Fs02
Copy link
Member

Fs02 commented Feb 19, 2025

Hi,

Is sending the field on the same function call is what you need?

Currently REL will include the field based on whether it's an association field or not. A dumb fallback now is to check if there's id field inside the record.

https://github.com/go-rel/rel/blob/master/document_meta.go#L264-L269

When it's detected as association, that field will be send as separate call.

One quick way I can think of is to add a new structag, that can be used to instruct rel to not treat the field as association 🤔

(Similar to structag used by embedded field)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants