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

@loader Issues #258

Closed
jonjondev opened this issue Jul 19, 2018 · 14 comments
Closed

@loader Issues #258

jonjondev opened this issue Jul 19, 2018 · 14 comments

Comments

@jonjondev
Copy link

Issue

I'm working on building out an API for myself and I'm currently trying to add persistence, however I get the following error from even a simple Example.all.

in lib/granite/src/granite/collection.cr:4: instance variable '@loader' of Granite::Collection(Example) must be Proc(Array(Example)), not Proc(Array(Example))

  def initialize(@loader : -> Array(M))

I looked over issue #244 the other day in search of answers and the workaround provided isn't quite enough for my purposes (plus it looks a little hacky). There seems to be no documentation for the syntax described in the issue, and all I really want to do here is to call .all, .find, .create, and .update. I don't have many dependencies for it to be clashing with unlike the other poster, and I'm not trying to do anything all that complex at this point.

So my question:

  1. Is there potential for this to be fixed in a release in the near future, and if not;
  2. Is there more comprehensive documentation on this other syntax?

Additional Code for Reference

shards.lock

version: 1.0
shards:
  db:
    github: crystal-lang/crystal-db
    version: 0.5.0

  granite:
    github: amberframework/granite
    version: 0.12.1

  inflector:
    github: phoffer/inflector.cr
    version: 0.1.8

  mime-types:
    github: jwaldrip/mime-types-cr
    version: 1.3.0

  oak:
    github: obsidian/oak
    version: 2.0.1

  orion:
    github: obsidian/orion
    version: 1.5.0

  pg:
    github: will/crystal-pg
    version: 0.15.0

all my requirements

# Library Requirements
require "orion"
require "json"
require "granite/adapter/pg"

calling my helper

# Includes
include Frost::ModelHelper

# Migrate DB
initialise_tables [User, Example]

model helper

module Frost::ModelHelper
  def initialise_tables(models : Array(Granite::Base.class))
    puts "Initialising tables..."
    tables_existed = 0
    models.each do |model|
      begin
        model.migrator.create
        puts "#{model} table created"
      rescue
        tables_existed += 1
      end
    end
    created = models.size - tables_existed
    puts "#{created} new #{pluralize("table", created)} created of #{models.size} #{pluralize("model", models.size)}"
  end

  def pluralize(singular : String, value : Int32)
    value == 1 ? singular : singular + 's'
  end
end

my user model

class User < Granite::Base
  extend Granite::Query::BuilderMethods
  adapter pg

  # Fields
  timestamps
  primary id : Int64
  field first_name : String
  field last_name : String
  field email : String
  field password_hash : String

  # Object methods
  def full_name
    "#{first_name} #{last_name}"
  end
end

my example model

class Example < Granite::Base
  extend Granite::Query::BuilderMethods

  adapter pg

  # Fields
  timestamps
  primary id : Int64
  field name : String
  field body : String

  # Object methods
end

the api method calling it

def index
    Example.create(name: "Test", body: "Data")
    respond Example.all
end

the full error (up to relevant trace)

instantiating 'ExampleApi#index()'
in src/api/example_api.cr:6: instantiating 'Example:Class#all()'

    respond Example.all
                    ^~~

in lib/granite/src/granite/querying.cr:52: instantiating 'all(String, Array(Bool | Float32 | Float64 | Int32 | Int64 | Slice(UInt8) | String | Time | Nil))'

  def all(clause = "", params = [] of DB::Any)
  ^

in lib/granite/src/granite/querying.cr:53: instantiating 'Granite::Collection(Example):Class#new(Proc(Array(Example)))'

    Collection(self).new(->{ raw_all(clause, params) })
                     ^~~

in lib/granite/src/granite/collection.cr:4: instance variable '@loader' of Granite::Collection(Example) must be Proc(Array(Example)), not Proc(Array(Example))

  def initialize(@loader : -> Array(M))
                 ^~~~~~~
@jonjondev jonjondev changed the title @loader Issues (i.e. nothing is working) @loader Issues Jul 19, 2018
@asterite
Copy link

This error can happen if you have both a public and a private class Example. The error is a bit misleading. Not sure this is the case, though, you'd have to check if there's a private class Example somewhere in amber that is somehow being used...

@robacarp
Copy link
Member

I think @asterite is right, this is due to there being a duplicate name in the class namespace somewhere. I don't think Granite has any class called Example, and on #244 the error was more specific and certainly didn't include anything that is part of Granite.

@J-Mo63 the query syntax in #244 is not documented because it's not solidified and not available for use with mysql and sqlite yet. As a result, it's only available my manually importing the DSL into a model.

Thanks for stopping by @asterite

@jonjondev
Copy link
Author

Hmm, it doesn't seem to be a conflict in my class naming however I could be wrong so this is the repo for reference.

After doing a find all in my project files (and not coming up with any other results), purging my lib, name-spacing my models, and changing their names, I still receive the loader issue:

the new model

module Frost
  class Abcd < Granite::Base
    extend Granite::Query::BuilderMethods

    adapter pg

    # Fields
    timestamps
    primary id : Int64
    field name : String
    field body : String

    # Object methods
  end
end

table creation

# Migrate DB
initialise_tables [Frost::User, Frost::Abcd]

calling action

def index
    Frost::Abcd.create(name: "Test", body: "Data")
    respond Frost::Abcd.all
end

the current error

instantiating 'ExampleApi#index()'
in src/api/example_api.cr:6: instantiating 'Frost::Abcd:Class#all()'

    respond Frost::Abcd.all
                        ^~~

in lib/granite/src/granite/querying.cr:52: instantiating 'all(String, Array(Bool | Float32 | Float64 | Int32 | Int64 | Slice(UInt8) | String | Time | Nil))'

  def all(clause = "", params = [] of DB::Any)
  ^

in lib/granite/src/granite/querying.cr:53: instantiating 'Granite::Collection(Frost::Abcd):Class#new(Proc(Array(Frost::Abcd)))'

    Collection(self).new(->{ raw_all(clause, params) })
                     ^~~

in lib/granite/src/granite/collection.cr:4: instance variable '@loader' of Granite::Collection(Frost::Abcd) must be Proc(Array(Frost::Abcd)), not Proc(Array(Frost::Abcd))

  def initialize(@loader : -> Array(M))
                 ^~~~~~~

@Blacksmoke16
Copy link
Contributor

Blacksmoke16 commented Jul 20, 2018

I did some trial and error and seemed to narrow it down to something in the orion lib. Am able to get it to compile by commenting some stuff out (the stuff that imports from orion) and commenting out the require "orion"

I'll see if i can figure anything out.

Edit: Seems it narrows down further to mime-types-cr

@jonjondev
Copy link
Author

@Blacksmoke16 how did you narrow it down to the mime-types lib? I just read through its code and there don't seem to be any naming conflicts with Granite.

@Blacksmoke16
Copy link
Contributor

Could just be coincidence, but removing mime-types references from orion lib made the error go away.

🤷‍♂️

@jonjondev
Copy link
Author

Urgh, what a pain. I may end up switching routers if I can't figure this one out. Thank you for your input!

@Blacksmoke16
Copy link
Contributor

Blacksmoke16 commented Jul 21, 2018

I'd checkout https://github.com/amberframework/amber-router

@asterite
Copy link

I'd check if there are aliases in mime-types. There are some bugs related to alias types that might cause this problem.

@asterite
Copy link

For example:

class Session; end

alias CmdHandler = Array(Session)
CmdHandler.class

class Foo
  def initialize(@h : CmdHandler)
  end
end

class SmtpSession < Session
end

Foo.new([] of Session)

Gives:

Error in foo.cr:14: instantiating 'Foo:Class#new(Array(Session))'

Foo.new([] of Session)
    ^~~

in foo.cr:7: instance variable '@h' of Foo must be Array(Session), not Array(Session)

  def initialize(@h : CmdHandler)
                 ^~

It's basically crystal-lang/crystal#1346 , which I'll fix tomorrow.

@asterite
Copy link

(though it might happens with non-aliases, not sure, you'd have to reduce the codebase to find out...)

@jonjondev
Copy link
Author

Wow, so you fixed this for non-top-level alias definitions back in 2016 huh. I've managed to remove all uses of aliasing throughout Orion and its dependancies but no dice.

Any other major situation that can cause the @instance must be SameType, not SameType compile error?

@asterite
Copy link

It seems so :-P

You'll have to reduce the code to find out.

@jonjondev
Copy link
Author

So after demolishing all of Orion and Mime-Type's code, I got it working, but still couldn't pinpoint a single fix for it that I could push up to their repos. So in defeat, I moved some days ago to Toro, and it honestly suited my purposes better anyway (tree-oriented routing).

While I have learned many a thing about the language from this debacle, this is clearly not a Granite problem, so I'm going to close the issue.

Thanks for the very useful help and suggestions @asterite @Blacksmoke16 and @robacarp!

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

4 participants