/* Copyright (c) 2011-2022 Reliancy LLC Licensed under the GNU LESSER GENERAL PUBLIC LICENSE Version 3. You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html. You may not use this file except in compliance with the License. */ package com.reliancy.dbo; import java.math.BigDecimal; import java.sql.Date; import java.sql.Timestamp; import com.reliancy.rec.Rec; import com.reliancy.rec.Slot; /** * Logical field definition with persistence metadata. * *
A {@code Field} extends {@link Slot} to add persistence attributes like * primary key designation, generated-value behavior, and optional storage hints. It serves * as both a compile-time field descriptor and a runtime value accessor. * *
Convenience methods for creating common field types: *
{@code
* Field id = Field.Int("id").setPk(true).setAutoIncrement(true);
* Field name = Field.Str("name");
* Field age = Field.Int("age");
* Field salary = Field.Num("salary").setTypeParams("10,2"); // DECIMAL(10,2)
* Field birthDate = Field.Date("birth_date");
* Field createdAt = Field.DateTime("created_at");
* Field isActive = Field.Bool("is_active");
* }
*
* Fields provide fluent methods for building {@link Check} conditions: *
{@code
* Check filter = Field.NAME.eq("John")
* .and(Field.AGE.gte(18))
* .and(Field.STATUS.in("active", "pending"));
*
* Action query = terminal.begin()
* .load(PersonDBO.class)
* .filterBy(filter)
* .execute();
* }
*
* The {@link #getId()} method returns the backend storage identifier. If not explicitly set, * it defaults to the Java field name. The {@link #equals(String)} method checks both * the name and ID for matches (case-insensitive). * * @see Slot * @see Entity * @see DBO * @see Check */ public class Field extends Slot { public static Field Int(String name){ return new Field(name,Integer.class); } public static Field Str(String name){ return new Field(name,String.class); } public static Field Bool(String name){ return new Field(name,Boolean.class); } public static Field Float(String name){ return new Field(name,Float.class); } public static Field Num(String name){ return new Field(name,BigDecimal.class); } public static Field Date(String name){ return new Field(name,Date.class); } public static Field DateTime(String name){ return new Field(name,Timestamp.class); } public static Field Rec(String name){ Field ret= new Field(name,Rec.class); ret.setFormat("json"); return ret; } public static final int FLAG_PK =0x0100; // primary key public static final int FLAG_AUTOINC =0x0200; // auto-increment public static final int FLAG_UNIQUE =0x0400; // unique public static final int FLAG_INDEXED =0x0800; // indexed public static final int FLAG_FK =0x1000; // foreign key String id; String typeParams; public Field(String name) { super(name); this.raiseFlags(Field.FLAG_STORABLE); } public Field(String name,Class> typ) { super(name,typ); this.raiseFlags(Field.FLAG_STORABLE); } @Override public boolean equals(String str){ return super.equals(str) || (id!=null && id.equalsIgnoreCase(str)); } /** * Compares this Field with another object for equality. * Two Fields are considered equal if they have the same name (case-insensitive) * or if they have the same id (case-insensitive, if id is set). * * @param obj the object to compare with * @return true if the objects are equal, false otherwise */ @Override public boolean equals(Object obj){ if(this == obj) return true; if(obj == null) return false; // First check if names match (case-insensitive) for slot-like objects if(super.equals(obj)) return true; if(!(obj instanceof Field)) return false; Field other = (Field)obj; // If this Field has an id, check if it matches other's name or id if(id != null){ if(id.equalsIgnoreCase(other.getName())) return true; if(other.id != null && id.equalsIgnoreCase(other.id)) return true; } // If other Field has an id, check if it matches this name if(other.id != null && other.id.equalsIgnoreCase(getName())) return true; return false; } /** * Returns a hash code for this Field based on its name and id (case-insensitive). * * @return hash code value for this Field */ @Override public int hashCode(){ // Use name for hashCode (inherited from Slot) int result = super.hashCode(); // Also incorporate id if present if(id != null){ result = 31 * result + id.toLowerCase().hashCode(); } return result; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Field withId(String id) { setId(id); return this; } public boolean isPk() { return checkFlags(FLAG_PK); } public Field setPk(boolean pk) { if(pk) raiseFlags(FLAG_PK); else clearFlags(FLAG_PK); return this; } public boolean isAutoIncrement() { return checkFlags(FLAG_AUTOINC); } public Field setAutoIncrement(boolean pk) { if(pk) raiseFlags(FLAG_AUTOINC); else clearFlags(FLAG_AUTOINC); return this; } public String getTypeParams() { return typeParams; } public Field setTypeParams(String p) { typeParams=p; return this; } public Field nullable(boolean nullable) { if (nullable) { raiseFlags(FLAG_NULLABLE); } else { clearFlags(FLAG_NULLABLE); } return this; } public Check eq(Object... val) { return Check.eq(this,val); } public Check neq(Object... val) { return Check.neq(this,val); } public Check gt(Object... val) { return Check.gt(this,val); } public Check gte(Object... val) { return Check.gte(this,val); } public Check lt(Object... val) { return Check.lt(this,val); } public Check lte(Object... val) { return Check.lte(this,val); } public Check like(Object... val) { return Check.like(this,val); } public Check in(Object... val) { return Check.in(this,val); } }