Ultimate Guide to Open Source Contribution (Part 2)
Tags: opensource, apacheage, postgres
Published: 2023-07-29 11:40:53

In the [previous article](https://dev.to/titoausten/ultimate-guide-to-open-source-contribution-part-1-54c9), we presented a basic template to Open Source contributions and as stated also, we would be delving into how we can use that template to contribute to Apache **AGE**.

For a practical approach, we are looking at how the `cos()` function was implemented in AGE.

> Note: Before creating a function in AGE, it should  supported by Neo4j Cypher and/or PostgreSQL else there should be a very valid reason.

Firstly, we check similar functions to see the structure to follow accordingly and then implement in **age--1.3.0.sql** and **src/backend/utils/adt/agtype.c** files.

In **age--1.3.0.sql**, the function is declared:
```
CREATE FUNCTION ag_catalog.age_cos(variadic "any")
RETURNS agtype
LANGUAGE c
IMMUTABLE
PARALLEL SAFE
AS 'MODULE_PATHNAME';
```

Then the function is created or added in **agtype.c**:
```
PG_FUNCTION_INFO_V1(age_cos);

Datum age_cos(PG_FUNCTION_ARGS)
{
    int nargs;
    Datum *args;
    bool *nulls;
    Oid *types;
    agtype_value agtv_result;
    float8 angle;
    float8 result;
    bool is_null = true;

    /* extract argument values */
    nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);

    /* check number of args */
    if (nargs != 1)
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                        errmsg("cos() invalid number of arguments")));

    /* check for a null input */
    if (nargs < 0 || nulls[0])
        PG_RETURN_NULL();

    /*
     * cos() supports integer, float, and numeric or the agtype integer, float,
     * and numeric for the angle
     */

    angle = get_float_compatible_arg(args[0], types[0], "cos", &is_null);

    /* check for a agtype null input */
    if (is_null)
        PG_RETURN_NULL();

    /* We need the numeric input as a float8 so that we can pass it off to PG */
    result = DatumGetFloat8(DirectFunctionCall1(dcos,
                                                Float8GetDatum(angle)));

    /* build the result */
    agtv_result.type = AGTV_FLOAT;
    agtv_result.val.float_value = result;

    PG_RETURN_POINTER(agtype_value_to_agtype(&agtv_result));
}
```

After creating a function, you should also write tests for that function to ensure it works efficiently. These tests are added to files in the **regress/** directory in the repository depending on the function added. In the case of `cos()` function, the files we are interested in are **regress/expected/expr.out** and **regress/sql/expr.sql**.

These files are used to test the functions and compare the output of different files. If the output or result from **expr.sql** is different from that in **expr.out** then the tests will fail. Hence, ensure the tests pass before making a pull request.

**Conclusion**
This is just a basic guide to contributing to an open source project like AGE. The steps stated in the [first article](https://dev.to/titoausten/ultimate-guide-to-open-source-contribution-part-1-54c9) can be implemented in any project. Remember, the most important part of contribution is **testing**, this ensures you don't push a code that causes "hiroshima" to the project.

**References**
[Apache AGE website](https://age.apache.org)
[Apache AGE project](https://github.com/apache/age)