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

orm: support different foreign key types #19337

Merged
merged 6 commits into from
Sep 17, 2023
Merged

Conversation

Casper64
Copy link
Member

@Casper64 Casper64 commented Sep 12, 2023

Fix #18844

This pr adds the ability to have other V types as foreign keys, intead of only ints and improves checker errors.

For example it is now possible to have a primary field of type string:

[table: 'stations']
struct Station {
	id           string        [primary]
	name         string
	observations []Observation [fkey: 'station_id']
}

[table: 'observations']
struct Observation {
	ts              time.Time [sql_type: 'DATETIME']
	station_id      string    [sql: 'stationid']
	air_temperature f64       [sql: 'airTemperature']
}

At this moment it is hardcoded in the orm code that a sub struct must have a field id of type int which is used to join the two tables. This pr removes this restriction for arrays and joins the two tables on the primary key, so for the previous example it would evaluate to something like this:

SELECT FROM observations WHERE station_id == [value of Station.id]

Consequently, when a struct with struct arrays is inserted the last insert id is only fetched if the parent struct has a sql serial field: int [primary; sql: serial], else the value of the primary field from the parent struct is passed to the array values.

Example to clarify:

module main

import db.sqlite
import time

[table: 'stations']
struct Station {
	id           string        [primary]
	name         string
	observations []Observation [fkey: 'station_id']
}

[table: 'observations']
struct Observation {
	ts              time.Time [sql_type: 'DATETIME']
	station_id      string    [sql: 'stationid']
	air_temperature f64       [sql: 'airTemperature']
}

fn main() {
	db := sqlite.connect(':memory:')!
	sql db {
		create table Observation
		create table Station
	}!
	s := Station{
		id: 'AMS'
		name: 'amsterdam'
		observations: [
			Observation{
				ts: time.now()
				air_temperature: 20.5
			},
			Observation{
				ts: time.now()
				air_temperature: 23.2
			},
		]
	}
	sql db {
		insert s into Station
	}!
	result := sql db {
		select from Station
	}!
	println('Result: ${result}')
}
Result: [Station{
    id: 'AMS'
    name: 'amsterdam'
    observations: [Observation{
        ts: 2023-09-12 22:59:51
        station_id: 'AMS'
        air_temperature: 20.5
    }, Observation{
        ts: 2023-09-12 22:59:51
        station_id: 'AMS'
        air_temperature: 23.2
    }]
}]

🤖 Generated by Copilot at 80499d2

This pull request enhances the ORM module to support custom primary keys of different types and names for structs, and fixes some bugs and errors related to foreign keys and array fields. It also adds new tests and checks for the ORM features and queries in the vlib/v/tests and vlib/v/checker/tests directories.

🤖 Generated by Copilot at 80499d2

  • Add support for different types and names of primary keys in ORM (link, link, link, link, link, link, link, link, link, link, link, link, link, link, link)
  • Declare and use a new variable primary_typ in orm.v to store the type of the primary key field of a struct (link, link)
  • Assign the type of the current field to primary_typ if the field has the primary attribute in orm.v (link)
  • Add a new constant pkey_attr_name in orm.v to store the name of the primary attribute for struct fields (link)
  • Declare and use two new variables has_pkey_attr and pkey_field in orm.v to track whether the struct has a primary key field and what that field is (link, link)
  • Use the pkey_field instead of a hardcoded id field in the where_expr of the subquery for array fields in orm.v (link)
  • Use the primary_field variable instead of the primary_field_name variable to access the name, type, and attributes of the primary key field in c/orm.v (link, link, link)
  • Add a new variable is_serial in c/orm.v to store whether the primary key field has the sql: serial attribute, which means that the SQL table will generate the primary key value automatically (link)
  • Modify the logic for getting the primary key value for array fields depending on the value of is_serial in c/orm.v (link)
  • Modify the name and return type of the get_orm_struct_primary_field_name function to get_orm_struct_primary_field and ?ast.StructField, respectively, in c/orm.v (link)
  • Add two new structs ParentString and ChildString to the test file orm_sub_array_struct_test.v to test the case where the primary key field is a string instead of an int, and the foreign key field has a different name than the primary key field (link)
  • Add two new test functions test_orm_array_different_pkey_type and test_orm_relationship_different_pkey_type to the test file orm_sub_array_struct_test.v to test the insert and select queries and the relationship between the structs ParentString and ChildString (link, link)
  • Add error checks for missing or multiple primary keys in ORM (link, link, link, link, link, link, link, link)
    • Add a check for the existence of the struct field with the given name in the current table, and return an error if not found, in c/orm.v (link)
    • Modify the return type of the get_orm_current_table_field function to be an optional ast.StructField instead of a default ast.StructField, and use the none keyword instead of an empty struct field, to indicate the absence of a value, in c/orm.v (link, link)
    • Add a check for the existence and uniqueness of the primary key field in the struct, and return an error if not found or multiple, in orm.v (link)
    • Add two new test files orm_fkey_has_pkey.out and orm_fkey_has_pkey.vv to check the error message when a struct has an array field with a foreign key but no primary key (link, link)
    • Add two new test files orm_multiple_pkeys.out and orm_multiple_pkeys.vv to check the error message when a struct has more than one primary key field (link, link)
  • Improve the code readability and consistency for accessing struct fields in ORM (link, link, link, link)
    • Declare and use a new variable member_access_type in c/orm.v to store the operator for accessing struct fields, either . or -> depending on whether the struct is a pointer or not (link, link, link)
    • Move the declaration and initialization of the member_access_type variable to a later point, after the arrs variable is declared, in c/orm.v (link)
    • Declare and use a new variable selected_fields_idx in c/orm.v to store the index of the selected fields in the SQL query result, and increment it after each non-array and array field is processed, in c/orm.v (link, link, link)

@Casper64 Casper64 marked this pull request as draft September 16, 2023 19:26
@Casper64 Casper64 marked this pull request as ready for review September 16, 2023 19:45
Comment on lines +211 to +212
assert parent.name == new_parent.name
assert parent.children.len == 0
Copy link
Member

@spytheman spytheman Sep 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho moving those assertions right after line 197 will be clearer.
The lines in between do not affect the parent instance.

select from ChildString
}!

assert children.len == 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The children survived the death of their parents, nice.

Copy link
Member

@spytheman spytheman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work.

@spytheman spytheman added ORM Bugs/feature requests, that are related to the V ORM. Unit: cgen Bugs/feature requests, that are related to the default C generating backend. labels Sep 17, 2023
@spytheman spytheman merged commit 2002db7 into vlang:master Sep 17, 2023
47 checks passed
@Casper64 Casper64 deleted the orm_fkeys branch September 17, 2023 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ORM Bugs/feature requests, that are related to the V ORM. Unit: cgen Bugs/feature requests, that are related to the default C generating backend.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

v panic: sym invalid type when using orm foreign key
2 participants